Allow users to set privacy on imported reviews

or not import them at all. Fixes #252
This commit is contained in:
Mouse Reeve 2020-10-30 11:21:02 -07:00
parent 45f39fab48
commit 0b0de12968
8 changed files with 77 additions and 18 deletions

View file

@ -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()

View 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),
),
]

View file

@ -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)

View file

@ -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):

View file

@ -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)

View file

@ -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):

View file

@ -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.

View file

@ -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')