diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index ee4eefbdd..6ae7883ef 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -8,6 +8,10 @@ from django.db.models.fields.related_descriptors \ import ForwardManyToOneDescriptor +class ActivitySerializerError(ValueError): + ''' routine problems serializing activitypub json ''' + + class ActivityEncoder(JSONEncoder): ''' used to convert an Activity object into json ''' def default(self, o): @@ -66,7 +70,8 @@ class ActivityObject: value = kwargs[field.name] except KeyError: if field.default == MISSING: - raise TypeError('Missing required field: %s' % field.name) + raise ActivitySerializerError(\ + 'Missing required field: %s' % field.name) value = field.default setattr(self, field.name, value) @@ -74,7 +79,7 @@ class ActivityObject: def to_model(self, model, instance=None): ''' convert from an activity to a model instance ''' if not isinstance(self, model.activity_serializer): - raise TypeError('Wrong activity type for model') + raise ActivitySerializerError('Wrong activity type for model') # check for an existing instance, if we're not updating a known obj if not instance: @@ -136,6 +141,7 @@ def resolve_foreign_key(model, remote_id): ).first() if not result: - raise ValueError('Could not resolve remote_id in %s model: %s' % \ + raise ActivitySerializerError( + 'Could not resolve remote_id in %s model: %s' % \ (model.__name__, remote_id)) return result diff --git a/bookwyrm/connectors/bookwyrm_connector.py b/bookwyrm/connectors/bookwyrm_connector.py index 5ad795cd3..ecceb4570 100644 --- a/bookwyrm/connectors/bookwyrm_connector.py +++ b/bookwyrm/connectors/bookwyrm_connector.py @@ -79,10 +79,17 @@ class Connector(AbstractConnector): cover_data = data.get('attachment') if not cover_data: return None - cover_url = cover_data[0].get('url') - response = requests.get(cover_url) + try: + cover_url = cover_data[0].get('url') + except IndexError: + return None + try: + response = requests.get(cover_url) + except ConnectionError: + return None + if not response.ok: - response.raise_for_status() + return None image_name = str(uuid4()) + '.' + cover_url.split('.')[-1] image_content = ContentFile(response.content) diff --git a/bookwyrm/connectors/openlibrary.py b/bookwyrm/connectors/openlibrary.py index 9b8afaa6a..5c26ad45b 100644 --- a/bookwyrm/connectors/openlibrary.py +++ b/bookwyrm/connectors/openlibrary.py @@ -177,10 +177,9 @@ class Connector(AbstractConnector): ''' load that author ''' if not re.match(r'^OL\d+A$', olkey): raise ValueError('Invalid OpenLibrary author ID') - try: - return models.Author.objects.get(openlibrary_key=olkey) - except models.Author.DoesNotExist: - pass + author = models.Author.objects.filter(openlibrary_key=olkey).first() + if author: + return author url = '%s/authors/%s.json' % (self.base_url, olkey) data = get_data(url) diff --git a/bookwyrm/goodreads_import.py b/bookwyrm/goodreads_import.py index fe5ac56e2..d5c0ad420 100644 --- a/bookwyrm/goodreads_import.py +++ b/bookwyrm/goodreads_import.py @@ -20,7 +20,7 @@ def create_job(user, csv_file, include_reviews, 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.") + raise ValueError('Author, title, and isbn must be in data.') ImportItem(job=job, index=index, data=entry).save() return job @@ -41,8 +41,11 @@ def import_data(job_id): for item in job.items.all(): try: item.resolve() - except HTTPError: - pass + except: + item.fail_reason = 'Error loading book' + item.save() + continue + if item.book: item.save() results.append(item) @@ -51,7 +54,7 @@ def import_data(job_id): outgoing.handle_imported_book( job.user, item, job.include_reviews, job.privacy) else: - item.fail_reason = "Could not find a match for book" + item.fail_reason = 'Could not find a match for book' item.save() finally: create_notification(job.user, 'IMPORT', related_import=job) diff --git a/bookwyrm/incoming.py b/bookwyrm/incoming.py index e9c5f6a8b..c2c223bd7 100644 --- a/bookwyrm/incoming.py +++ b/bookwyrm/incoming.py @@ -238,7 +238,12 @@ def handle_create(activity): @app.task def handle_delete_status(activity): ''' remove a status ''' - status_id = activity['object']['id'] + try: + status_id = activity['object']['id'] + except TypeError: + # this isn't a great fix, because you hit this when mastadon + # is trying to delete a user. + return try: status = models.Status.objects.select_subclasses().get( remote_id=status_id @@ -282,7 +287,11 @@ def handle_unfavorite(activity): @app.task def handle_boost(activity): ''' someone gave us a boost! ''' - boost = activitypub.Boost(**activity).to_model(models.Boost) + try: + boost = activitypub.Boost(**activity).to_model(models.Boost) + except activitypub.ActivitySerializerError: + # this probably just means we tried to boost an unknown status + return if not boost.user.local: status_builder.create_notification( diff --git a/bookwyrm/remote_user.py b/bookwyrm/remote_user.py index b3408c712..9178451b4 100644 --- a/bookwyrm/remote_user.py +++ b/bookwyrm/remote_user.py @@ -37,10 +37,14 @@ def get_or_create_remote_user(actor): def fetch_user_data(actor): ''' load the user's info from the actor url ''' - response = requests.get( - actor, - headers={'Accept': 'application/activity+json'} - ) + try: + response = requests.get( + actor, + headers={'Accept': 'application/activity+json'} + ) + except ConnectionError: + return None + if not response.ok: response.raise_for_status() data = response.json() @@ -83,7 +87,10 @@ def get_avatar(data): @app.task def get_remote_reviews(user_id): ''' ingest reviews by a new remote bookwyrm user ''' - user = models.User.objects.get(id=user_id) + try: + user = models.User.objects.get(id=user_id) + except models.User.DoesNotExist: + return outbox_page = user.outbox + '?page=true' response = requests.get( outbox_page, diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index 5f87ee0a5..7bac49124 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -20,6 +20,7 @@ function reply(e) { return true; } + function rate_stars(e) { e.preventDefault(); ajaxPost(e.target); diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index 47b994830..b0064e1fd 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -55,7 +55,7 @@

{% include 'snippets/stars.html' with rating=rating %} ({{ reviews|length }} review{{ reviews|length|pluralize }})

- {% include 'snippets/book_description.html' %} + {% include 'snippets/trimmed_text.html' with full=book|book_description %} {% if book.parent_work.edition_set.count > 1 %}

{{ book.parent_work.edition_set.count }} editions

@@ -77,12 +77,12 @@ {% endif %}
-
-
diff --git a/bookwyrm/templates/import_status.html b/bookwyrm/templates/import_status.html index 7db2ba3d5..c1dbb26e2 100644 --- a/bookwyrm/templates/import_status.html +++ b/bookwyrm/templates/import_status.html @@ -6,29 +6,44 @@

Import Status

- Import started: {{ job.created_date | naturaltime }} + Import started: {{ job.created_date | naturaltime }} +

+ {% if task.successful %}

- {% if task.ready %} - Import completed: {{ task.date_done | naturaltime }} - {% if task.failed %} -

TASK FAILED

-

- {{ task.info }} + Import completed: {{ task.date_done | naturaltime }} +

+ {% elif task.failed %} +
TASK FAILED
{% endif %}
- {% if job.import_status %} - {% include 'snippets/status.html' with status=job.import_status %} - {% endif %} - {% else %} + {% if not task.ready %} Import still in progress.

- (Hit reload to update!) + (Hit reload to update!) +

{% endif %}
+{% if failed_items %}
+

Failed to load

+ +
+{% endif %} + +
+

Successfully imported

diff --git a/bookwyrm/templates/snippets/book_description.html b/bookwyrm/templates/snippets/book_description.html deleted file mode 100644 index 1352f6f59..000000000 --- a/bookwyrm/templates/snippets/book_description.html +++ /dev/null @@ -1,26 +0,0 @@ -{% load fr_display %} -{% with book.id|uuid as uuid %} -{% with book|book_description as full %} -{% if full %} - {% with full|text_overflow as trimmed %} - {% if trimmed != full %} -
- - -
-
- - -
- {% else %} -
{{ full }} -
- {% endif %} - {% endwith %} -{% endif %} -{% endwith %} -{% endwith %} diff --git a/bookwyrm/templates/snippets/book_preview.html b/bookwyrm/templates/snippets/book_preview.html index ab41d41ea..c675c45f0 100644 --- a/bookwyrm/templates/snippets/book_preview.html +++ b/bookwyrm/templates/snippets/book_preview.html @@ -1,3 +1,4 @@ +{% load fr_display %}
@@ -7,6 +8,6 @@

{% include 'snippets/book_titleby.html' with book=book %}

- {% include 'snippets/book_description.html' with book=book %} + {% include 'snippets/trimmed_text.html' with full=book|book_description %}
diff --git a/bookwyrm/templates/snippets/status_body.html b/bookwyrm/templates/snippets/status_body.html index 2bd1d6eb5..4ef763fb4 100644 --- a/bookwyrm/templates/snippets/status_body.html +++ b/bookwyrm/templates/snippets/status_body.html @@ -18,24 +18,13 @@
@@ -59,9 +74,10 @@ {{ item.data|dict_key:'Author' }} - {% if item.book %}✓ - {% elif item.fail_reason %} - {{ item.fail_reason }} + {% if item.book %} + + Imported + {% endif %}