forked from mirrors/bookwyrm
Allow users to set privacy on imported reviews
or not import them at all. Fixes #252
This commit is contained in:
parent
45f39fab48
commit
0b0de12968
8 changed files with 77 additions and 18 deletions
|
@ -11,9 +11,13 @@ from bookwyrm.status import create_notification
|
|||
MAX_ENTRIES = 500
|
||||
|
||||
|
||||
def create_job(user, csv_file):
|
||||
def create_job(user, csv_file, include_reviews, privacy):
|
||||
''' check over a csv and creates a database entry for the job'''
|
||||
job = ImportJob.objects.create(user=user)
|
||||
job = ImportJob.objects.create(
|
||||
user=user,
|
||||
include_reviews=include_reviews,
|
||||
privacy=privacy
|
||||
)
|
||||
for index, entry in enumerate(list(csv.DictReader(csv_file))[:MAX_ENTRIES]):
|
||||
if not all(x in entry for x in ('ISBN13', 'Title', 'Author')):
|
||||
raise ValueError("Author, title, and isbn must be in data.")
|
||||
|
@ -42,8 +46,10 @@ def import_data(job_id):
|
|||
if item.book:
|
||||
item.save()
|
||||
results.append(item)
|
||||
# shelves book and handles reviews
|
||||
outgoing.handle_imported_book(job.user, item)
|
||||
|
||||
if job.include_reviews:
|
||||
# shelves book and handles reviews
|
||||
outgoing.handle_imported_book(job.user, item, job.privacy)
|
||||
else:
|
||||
item.fail_reason = "Could not find a match for book"
|
||||
item.save()
|
||||
|
|
23
bookwyrm/migrations/0059_auto_20201030_1755.py
Normal file
23
bookwyrm/migrations/0059_auto_20201030_1755.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.0.7 on 2020-10-30 17:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bookwyrm', '0058_remove_importjob_import_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='importjob',
|
||||
name='include_reviews',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='importjob',
|
||||
name='privacy',
|
||||
field=models.CharField(choices=[('public', 'Public'), ('unlisted', 'Unlisted'), ('followers', 'Followers'), ('direct', 'Direct')], default='public', max_length=255),
|
||||
),
|
||||
]
|
|
@ -14,6 +14,14 @@ from django.dispatch import receiver
|
|||
from bookwyrm import activitypub
|
||||
from bookwyrm.settings import DOMAIN
|
||||
|
||||
|
||||
PrivacyLevels = models.TextChoices('Privacy', [
|
||||
'public',
|
||||
'unlisted',
|
||||
'followers',
|
||||
'direct'
|
||||
])
|
||||
|
||||
class BookWyrmModel(models.Model):
|
||||
''' shared fields '''
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
|
|
@ -9,6 +9,8 @@ from bookwyrm import books_manager
|
|||
from bookwyrm.connectors import ConnectorException
|
||||
from bookwyrm.models import ReadThrough, User, Book
|
||||
from bookwyrm.utils.fields import JSONField
|
||||
from .base_model import PrivacyLevels
|
||||
|
||||
|
||||
# Mapping goodreads -> bookwyrm shelf titles.
|
||||
GOODREADS_SHELVES = {
|
||||
|
@ -40,6 +42,12 @@ class ImportJob(models.Model):
|
|||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_date = models.DateTimeField(default=timezone.now)
|
||||
task_id = models.CharField(max_length=100, null=True)
|
||||
include_reviews = models.BooleanField(default=True)
|
||||
privacy = models.CharField(
|
||||
max_length=255,
|
||||
default='public',
|
||||
choices=PrivacyLevels.choices
|
||||
)
|
||||
|
||||
|
||||
class ImportItem(models.Model):
|
||||
|
|
|
@ -7,16 +7,9 @@ from model_utils.managers import InheritanceManager
|
|||
|
||||
from bookwyrm import activitypub
|
||||
from .base_model import ActivitypubMixin, OrderedCollectionPageMixin
|
||||
from .base_model import ActivityMapping, BookWyrmModel
|
||||
from .base_model import ActivityMapping, BookWyrmModel, PrivacyLevels
|
||||
|
||||
|
||||
PrivacyLevels = models.TextChoices('Privacy', [
|
||||
'public',
|
||||
'unlisted',
|
||||
'followers',
|
||||
'direct'
|
||||
])
|
||||
|
||||
class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||
''' any post, like a reply to a review, etc '''
|
||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
|
|
|
@ -155,7 +155,7 @@ def handle_unshelve(user, book, shelf):
|
|||
broadcast(user, activity)
|
||||
|
||||
|
||||
def handle_imported_book(user, item):
|
||||
def handle_imported_book(user, item, privacy):
|
||||
''' process a goodreads csv and then post about it '''
|
||||
if isinstance(item.book, models.Work):
|
||||
item.book = item.book.default_edition
|
||||
|
@ -171,7 +171,7 @@ def handle_imported_book(user, item):
|
|||
shelf_book, created = models.ShelfBook.objects.get_or_create(
|
||||
book=item.book, shelf=desired_shelf, added_by=user)
|
||||
if created:
|
||||
broadcast(user, shelf_book.to_add_activity(user))
|
||||
broadcast(user, shelf_book.to_add_activity(user), privacy=privacy)
|
||||
|
||||
# only add new read-throughs if the item isn't already shelved
|
||||
for read in item.reads:
|
||||
|
@ -194,10 +194,11 @@ def handle_imported_book(user, item):
|
|||
content=item.review,
|
||||
rating=item.rating,
|
||||
published_date=published_date_guess,
|
||||
privacy=privacy,
|
||||
)
|
||||
# we don't need to send out pure activities because non-bookwyrm
|
||||
# instances don't need this data
|
||||
broadcast(user, review.to_create_activity(user))
|
||||
broadcast(user, review.to_create_activity(user), privacy=privacy)
|
||||
|
||||
|
||||
def handle_delete_status(user, status):
|
||||
|
|
|
@ -5,8 +5,24 @@
|
|||
<h2 class="title">Import Books from GoodReads</h2>
|
||||
<form name="import" action="/import_data/" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ import_form.as_p }}
|
||||
<button class="button" type="submit">Import</button>
|
||||
<div class="field">
|
||||
{{ import_form.as_p }}
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="include_reviews"><input type="checkbox" name="include_reviews" checked> Include reviews</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="privacy">Privacy setting for imported reviews</label>
|
||||
<div class="select">
|
||||
<select name="privacy">
|
||||
<option value="public" selected>Public</option>
|
||||
<option value="unlisted">Unlisted</option>
|
||||
<option value="followers">Followers only</option>
|
||||
<option value="direct">Private</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button class="button is-primary" type="submit">Import</button>
|
||||
</form>
|
||||
<p>
|
||||
Imports are limited in size, and only the first {{ limit }} items will be imported.
|
||||
|
|
|
@ -491,12 +491,16 @@ def import_data(request):
|
|||
''' ingest a goodreads csv '''
|
||||
form = forms.ImportForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
include_reviews = request.POST.get('include_reviews') == 'on'
|
||||
privacy = request.POST.get('privacy')
|
||||
try:
|
||||
job = goodreads_import.create_job(
|
||||
request.user,
|
||||
TextIOWrapper(
|
||||
request.FILES['csv_file'],
|
||||
encoding=request.encoding)
|
||||
encoding=request.encoding),
|
||||
include_reviews,
|
||||
privacy,
|
||||
)
|
||||
except (UnicodeDecodeError, ValueError):
|
||||
return HttpResponseBadRequest('Not a valid csv file')
|
||||
|
|
Loading…
Reference in a new issue