From 54687b7b358bdbd957feda7bb01c96e8bd4f2db4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Feb 2021 13:45:49 -0800 Subject: [PATCH 01/58] Make users editors by default --- bookwyrm/models/user.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index f137236c0..21ef8dd2d 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -3,7 +3,7 @@ import re from urllib.parse import urlparse from django.apps import apps -from django.contrib.auth.models import AbstractUser +from django.contrib.auth.models import AbstractUser, Group from django.core.validators import MinValueValidator from django.db import models from django.utils import timezone @@ -208,6 +208,9 @@ class User(OrderedCollectionPageMixin, AbstractUser): # an id needs to be set before we can proceed with related models super().save(*args, **kwargs) + # make users editors by default + self.groups.add(Group.objects.get(name='editor')) + # create keys and shelves for new local users self.key_pair = KeyPair.objects.create( remote_id='%s/#main-key' % self.remote_id) From 714e1f3809a667d2ae2dca6ae7d557073f9e56c3 Mon Sep 17 00:00:00 2001 From: erion Date: Wed, 3 Mar 2021 12:11:28 +0100 Subject: [PATCH 02/58] Reduce Dockerfile size and the number of RUN steps. --- Dockerfile | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 99d2671ce..0f10015c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,15 +2,12 @@ FROM python:3.9 ENV PYTHONUNBUFFERED 1 -RUN mkdir /app -RUN mkdir /app/static -RUN mkdir /app/images +RUN mkdir /app /app/static /app/images WORKDIR /app COPY requirements.txt /app/ -RUN pip install -r requirements.txt -RUN apt-get update && apt-get install -y gettext libgettextpo-dev +RUN pip install -r requirements.txt --no-cache-dir +RUN apt-get update && apt-get install -y gettext libgettextpo-dev && apt-get clean -COPY ./bookwyrm /app -COPY ./celerywyrm /app +COPY ./bookwyrm ./celerywyrm /app/ From 0d8eb959ea6a68c7db88f729747a9e413525e8a8 Mon Sep 17 00:00:00 2001 From: Fabien Basmaison Date: Wed, 3 Mar 2021 15:48:04 +0100 Subject: [PATCH 03/58] [profile] Use unique IDs on statuses. --- bookwyrm/templates/user/user.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/user/user.html b/bookwyrm/templates/user/user.html index 5dd24caee..cefaab99f 100644 --- a/bookwyrm/templates/user/user.html +++ b/bookwyrm/templates/user/user.html @@ -67,7 +67,7 @@ {% for activity in activities %} -
+
{% include 'snippets/status/status.html' with status=activity %}
{% endfor %} From a05b14c338aeab3471f0416d5d5ee793c26f7067 Mon Sep 17 00:00:00 2001 From: Fabien Basmaison Date: Wed, 3 Mar 2021 20:10:09 +0100 Subject: [PATCH 04/58] [profile] Various HTML fixes: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap block level elements within block level elements, not inline. - Avoid empty blocks. - Change `
` in lists into allowed type of children. - Fix duplicated ID (some change that was not propagated across the template?). - Make the anchor optional in the navbar (interactive elements (`a`, `input`, `button`…) should not appear into other interactive elements). - Remove redundant `role` on main navigation. - Make the modal a modal with `role="dialog". - Use `button` instead of form-less `label`. --- bookwyrm/templates/components/dropdown.html | 2 +- bookwyrm/templates/components/modal.html | 11 ++++++--- bookwyrm/templates/layout.html | 22 +++++++++++------ .../templates/snippets/shelf_selector.html | 2 +- .../snippets/status/status_content.html | 8 ++++--- bookwyrm/templates/snippets/trimmed_text.html | 24 +++++++++++++------ bookwyrm/templates/snippets/username.html | 15 +++++++++++- 7 files changed, 61 insertions(+), 23 deletions(-) diff --git a/bookwyrm/templates/components/dropdown.html b/bookwyrm/templates/components/dropdown.html index 1e45fe51a..72582ddc3 100644 --- a/bookwyrm/templates/components/dropdown.html +++ b/bookwyrm/templates/components/dropdown.html @@ -5,7 +5,7 @@ {% block dropdown-trigger %}{% endblock %} diff --git a/bookwyrm/templates/components/modal.html b/bookwyrm/templates/components/modal.html index 554f9ccde..1110a8eea 100644 --- a/bookwyrm/templates/components/modal.html +++ b/bookwyrm/templates/components/modal.html @@ -1,8 +1,13 @@ - -{% endblock %} +{% endspaceless %}{% endblock %} diff --git a/locale/fr_FR/LC_MESSAGES/django.mo b/locale/fr_FR/LC_MESSAGES/django.mo index 2cddb7935337507fcce9245e070abe10274ca6fb..2620d2499b37f4a2772a7de337251835e38f686a 100644 GIT binary patch delta 7753 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 diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index 49f43c4cd..1f85035b2 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-03-04 22:24+0000\n" +"POT-Creation-Date: 2021-03-05 14:10+0000\n" "PO-Revision-Date: 2021-03-02 12:37+0100\n" "Last-Translator: Fabien Basmaison \n" "Language-Team: Mouse Reeve \n" @@ -613,37 +613,42 @@ msgstr "(Rechargez la page pour mettre à jour !" #: bookwyrm/templates/import_status.html:35 msgid "Failed to load" -msgstr "Le chargement a échoué" +msgstr "Items non importés" -#: bookwyrm/templates/import_status.html:59 +#: bookwyrm/templates/import_status.html:42 +#, python-format +msgid "Jump to the bottom of the list to select the %(failed_count)s items which failed to import." +msgstr "Sauter en bas de liste pour sélectionner les %(failed_count)s items n’ayant pu être importés." + +#: bookwyrm/templates/import_status.html:74 msgid "Select all" msgstr "Tout sélectionner" -#: bookwyrm/templates/import_status.html:62 +#: bookwyrm/templates/import_status.html:79 msgid "Retry items" -msgstr "Essayer d’importer les objets sélectionnés de nouveau" +msgstr "Essayer d’importer les items sélectionnés de nouveau" -#: bookwyrm/templates/import_status.html:84 +#: bookwyrm/templates/import_status.html:101 msgid "Successfully imported" msgstr "Importation réussie" -#: bookwyrm/templates/import_status.html:88 +#: bookwyrm/templates/import_status.html:105 #: bookwyrm/templates/lists/curate.html:14 msgid "Book" msgstr "Livre" -#: bookwyrm/templates/import_status.html:91 +#: bookwyrm/templates/import_status.html:108 #: bookwyrm/templates/snippets/create_status_form.html:10 #: bookwyrm/templates/snippets/shelf.html:10 msgid "Title" msgstr "Titre" -#: bookwyrm/templates/import_status.html:94 +#: bookwyrm/templates/import_status.html:111 #: bookwyrm/templates/snippets/shelf.html:11 msgid "Author" msgstr "Auteur ou autrice" -#: bookwyrm/templates/import_status.html:117 +#: bookwyrm/templates/import_status.html:134 msgid "Imported" msgstr "Importé" From b70e728ffb816574f68433b7ff5c1c1441217ac2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 5 Mar 2021 06:58:22 -0800 Subject: [PATCH 30/58] Removes the word "cover" from cover alt text Fixes #694 --- bookwyrm/models/book.py | 2 +- bookwyrm/tests/models/test_book_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index f1f208303..6a1a18b1e 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -91,7 +91,7 @@ class Book(BookDataModel): @property def alt_text(self): ''' image alt test ''' - text = '%s cover' % self.title + text = '%s' % self.title if self.edition_info: text += ' (%s)' % self.edition_info return text diff --git a/bookwyrm/tests/models/test_book_model.py b/bookwyrm/tests/models/test_book_model.py index 98d6d446e..b4a099d05 100644 --- a/bookwyrm/tests/models/test_book_model.py +++ b/bookwyrm/tests/models/test_book_model.py @@ -81,7 +81,7 @@ class Book(TestCase): book.save() self.assertEqual(book.edition_info, 'worm, Glorbish language, 2020') self.assertEqual( - book.alt_text, 'Test Edition cover (worm, Glorbish language, 2020)') + book.alt_text, 'Test Edition (worm, Glorbish language, 2020)') def test_get_rank(self): From 91a14d3a1334848132a0474824da8b2ce054f185 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 5 Mar 2021 07:50:23 -0800 Subject: [PATCH 31/58] Updates alt text in status model tests --- bookwyrm/tests/models/test_status_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index c6911b6df..29be5c072 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -150,7 +150,7 @@ class Status(TestCase): self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ (settings.DOMAIN, self.book.cover.url)) self.assertEqual( - activity['attachment'][0].name, 'Test Edition cover') + activity['attachment'][0].name, 'Test Edition') def test_comment_to_activity(self, _): ''' subclass of the base model version with a "pure" serializer ''' @@ -177,7 +177,7 @@ class Status(TestCase): self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ (settings.DOMAIN, self.book.cover.url)) self.assertEqual( - activity['attachment'][0].name, 'Test Edition cover') + activity['attachment'][0].name, 'Test Edition') def test_quotation_to_activity(self, _): ''' subclass of the base model version with a "pure" serializer ''' @@ -207,7 +207,7 @@ class Status(TestCase): self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ (settings.DOMAIN, self.book.cover.url)) self.assertEqual( - activity['attachment'][0].name, 'Test Edition cover') + activity['attachment'][0].name, 'Test Edition') def test_review_to_activity(self, _): ''' subclass of the base model version with a "pure" serializer ''' @@ -238,7 +238,7 @@ class Status(TestCase): self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ (settings.DOMAIN, self.book.cover.url)) self.assertEqual( - activity['attachment'][0].name, 'Test Edition cover') + activity['attachment'][0].name, 'Test Edition') def test_favorite(self, _): ''' fav a status ''' From 99e5e3e414386bae121cd4da0cd2d2db350916e5 Mon Sep 17 00:00:00 2001 From: Fabien Basmaison Date: Fri, 5 Mar 2021 22:09:56 +0100 Subject: [PATCH 32/58] [import] Show skip link to all when there is more than 10 failed imports. --- bookwyrm/static/css/format.css | 5 +++++ bookwyrm/templates/import_status.html | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bookwyrm/static/css/format.css b/bookwyrm/static/css/format.css index 92e0d92c7..9badfaf0b 100644 --- a/bookwyrm/static/css/format.css +++ b/bookwyrm/static/css/format.css @@ -1,3 +1,8 @@ +html { + scroll-behavior: smooth; + scroll-padding-top: 20%; +} + /* --- --- */ .image { overflow: hidden; diff --git a/bookwyrm/templates/import_status.html b/bookwyrm/templates/import_status.html index 3ee9c4a58..f9ba36bf4 100644 --- a/bookwyrm/templates/import_status.html +++ b/bookwyrm/templates/import_status.html @@ -38,9 +38,13 @@ {% csrf_token %} {% with failed_count=failed_items|length %} - + {% if failed_count > 10 %} +

+ + {% blocktrans %}Jump to the bottom of the list to select the {{ failed_count }} items which failed to import.{% endblocktrans %} + +

+ {% endif %} {% endwith %}
@@ -64,7 +68,7 @@
-

From 703ff60271fe4ad36bf2210949e0b375998df084 Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Mon, 1 Mar 2021 21:09:21 +0100 Subject: [PATCH 33/58] isbn search --- bookwyrm/connectors/abstract_connector.py | 33 ++++++++++++ bookwyrm/connectors/bookwyrm_connector.py | 8 +++ bookwyrm/connectors/connector_manager.py | 33 ++++++++++-- bookwyrm/connectors/openlibrary.py | 16 ++++++ bookwyrm/connectors/self_connector.py | 42 +++++++++++++++ bookwyrm/management/commands/initdb.py | 3 ++ .../0047_connector_isbn_search_url.py | 18 +++++++ bookwyrm/models/connector.py | 1 + bookwyrm/templates/isbn_search_results.html | 33 ++++++++++++ .../connectors/test_abstract_connector.py | 4 ++ .../test_abstract_minimal_connector.py | 6 +++ .../connectors/test_openlibrary_connector.py | 29 ++++++++++ bookwyrm/tests/data/ol_isbn_search.json | 45 ++++++++++++++++ bookwyrm/tests/views/test_isbn.py | 54 +++++++++++++++++++ bookwyrm/tests/views/test_search.py | 4 ++ bookwyrm/urls.py | 3 ++ bookwyrm/views/__init__.py | 1 + bookwyrm/views/isbn.py | 29 ++++++++++ 18 files changed, 358 insertions(+), 4 deletions(-) create mode 100644 bookwyrm/migrations/0047_connector_isbn_search_url.py create mode 100644 bookwyrm/templates/isbn_search_results.html create mode 100644 bookwyrm/tests/data/ol_isbn_search.json create mode 100644 bookwyrm/tests/views/test_isbn.py create mode 100644 bookwyrm/views/isbn.py diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index 68ff2a483..e6372438e 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -26,6 +26,7 @@ class AbstractMinimalConnector(ABC): 'books_url', 'covers_url', 'search_url', + 'isbn_search_url', 'max_query_count', 'name', 'identifier', @@ -61,6 +62,30 @@ class AbstractMinimalConnector(ABC): results.append(self.format_search_result(doc)) return results + def isbn_search(self, query): + ''' isbn search ''' + params = {} + resp = requests.get( + '%s%s' % (self.isbn_search_url, query), + params=params, + headers={ + 'Accept': 'application/json; charset=utf-8', + 'User-Agent': settings.USER_AGENT, + }, + ) + if not resp.ok: + resp.raise_for_status() + try: + data = resp.json() + except ValueError as e: + logger.exception(e) + raise ConnectorException('Unable to parse json response', e) + results = [] + + for doc in self.parse_isbn_search_data(data): + results.append(self.format_isbn_search_result(doc)) + return results + @abstractmethod def get_or_create_book(self, remote_id): ''' pull up a book record by whatever means possible ''' @@ -73,6 +98,14 @@ class AbstractMinimalConnector(ABC): def format_search_result(self, search_result): ''' create a SearchResult obj from json ''' + @abstractmethod + def parse_isbn_search_data(self, data): + ''' turn the result json from a search into a list ''' + + @abstractmethod + def format_isbn_search_result(self, search_result): + ''' create a SearchResult obj from json ''' + class AbstractConnector(AbstractMinimalConnector): ''' generic book data connector ''' diff --git a/bookwyrm/connectors/bookwyrm_connector.py b/bookwyrm/connectors/bookwyrm_connector.py index 00e6c62f1..96b72f267 100644 --- a/bookwyrm/connectors/bookwyrm_connector.py +++ b/bookwyrm/connectors/bookwyrm_connector.py @@ -19,3 +19,11 @@ class Connector(AbstractMinimalConnector): def format_search_result(self, search_result): search_result['connector'] = self return SearchResult(**search_result) + + def parse_isbn_search_data(self, data): + return data + + def format_isbn_search_result(self, search_result): + search_result['connector'] = self + return SearchResult(**search_result) + diff --git a/bookwyrm/connectors/connector_manager.py b/bookwyrm/connectors/connector_manager.py index a63a788eb..053e1f9ef 100644 --- a/bookwyrm/connectors/connector_manager.py +++ b/bookwyrm/connectors/connector_manager.py @@ -1,5 +1,6 @@ ''' interface with whatever connectors the app has ''' import importlib +import re from urllib.parse import urlparse from requests import HTTPError @@ -15,13 +16,31 @@ class ConnectorException(HTTPError): def search(query, min_confidence=0.1): ''' find books based on arbitary keywords ''' results = [] + + # Have we got a ISBN ? + isbn = re.sub('[\W_]', '', query) + maybe_isbn = len(isbn) in [10, 13] # ISBN10 or ISBN13 + dedup_slug = lambda r: '%s/%s/%s' % (r.title, r.author, r.year) result_index = set() for connector in get_connectors(): - try: - result_set = connector.search(query, min_confidence=min_confidence) - except (HTTPError, ConnectorException): - continue + result_set = None + if maybe_isbn: + # Search on ISBN + if not connector.isbn_search_url or connector.isbn_search_url == '': + result_set = [] + else: + try: + result_set = connector.isbn_search(isbn) + except (HTTPError, ConnectorException): + pass + + # if no isbn search or results, we fallback to generic search + if result_set == None or result_set == []: + try: + result_set = connector.search(query, min_confidence=min_confidence) + except (HTTPError, ConnectorException): + continue result_set = [r for r in result_set \ if dedup_slug(r) not in result_index] @@ -41,6 +60,12 @@ def local_search(query, min_confidence=0.1, raw=False): return connector.search(query, min_confidence=min_confidence, raw=raw) +def isbn_local_search(query, raw=False): + ''' only look at local search results ''' + connector = load_connector(models.Connector.objects.get(local=True)) + return connector.isbn_search(query, raw=raw) + + def first_search_result(query, min_confidence=0.1): ''' search until you find a result that fits ''' for connector in get_connectors(): diff --git a/bookwyrm/connectors/openlibrary.py b/bookwyrm/connectors/openlibrary.py index a767a45ac..8d227eef1 100644 --- a/bookwyrm/connectors/openlibrary.py +++ b/bookwyrm/connectors/openlibrary.py @@ -129,6 +129,22 @@ class Connector(AbstractConnector): ) + def parse_isbn_search_data(self, data): + return list(data.values()) + + def format_isbn_search_result(self, search_result): + # build the remote id from the openlibrary key + key = self.books_url + search_result['key'] + authors = search_result.get('authors') or [{'name': 'Unknown'}] + author_names = [ author.get('name') for author in authors] + return SearchResult( + title=search_result.get('title'), + key=key, + author=', '.join(author_names), + connector=self, + year=search_result.get('publish_date'), + ) + def load_edition_data(self, olkey): ''' query openlibrary for editions of a work ''' url = '%s/works/%s/editions' % (self.books_url, olkey) diff --git a/bookwyrm/connectors/self_connector.py b/bookwyrm/connectors/self_connector.py index f57fbc1cc..b3a4d6f9f 100644 --- a/bookwyrm/connectors/self_connector.py +++ b/bookwyrm/connectors/self_connector.py @@ -33,6 +33,31 @@ class Connector(AbstractConnector): search_results.sort(key=lambda r: r.confidence, reverse=True) return search_results + def isbn_search(self, query, raw=False): + ''' search your local database ''' + if not query: + return [] + + filters = [{f: query} for f in ['isbn_10', 'isbn_13']] + results = models.Edition.objects.filter( + reduce(operator.or_, (Q(**f) for f in filters)) + ).distinct() + + # when there are multiple editions of the same work, pick the default. + # it would be odd for this to happen. + results = results.filter(parent_work__default_edition__id=F('id')) \ + or results + + search_results = [] + for result in results: + if raw: + search_results.append(result) + else: + search_results.append(self.format_search_result(result)) + if len(search_results) >= 10: + break + return search_results + def format_search_result(self, search_result): return SearchResult( @@ -47,6 +72,19 @@ class Connector(AbstractConnector): ) + def format_isbn_search_result(self, search_result): + return SearchResult( + title=search_result.title, + key=search_result.remote_id, + author=search_result.author_text, + year=search_result.published_date.year if \ + search_result.published_date else None, + connector=self, + confidence=search_result.rank if \ + hasattr(search_result, 'rank') else 1, + ) + + def is_work_data(self, data): pass @@ -59,6 +97,10 @@ class Connector(AbstractConnector): def get_authors_from_data(self, data): return None + def parse_isbn_search_data(self, data): + ''' it's already in the right format, don't even worry about it ''' + return data + def parse_search_data(self, data): ''' it's already in the right format, don't even worry about it ''' return data diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index 9fd117871..5759abfcc 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -66,6 +66,7 @@ def init_connectors(): books_url='https://%s/book' % DOMAIN, covers_url='https://%s/images/covers' % DOMAIN, search_url='https://%s/search?q=' % DOMAIN, + isbn_search_url='https://%s/isbn/' % DOMAIN, priority=1, ) @@ -77,6 +78,7 @@ def init_connectors(): books_url='https://bookwyrm.social/book', covers_url='https://bookwyrm.social/images/covers', search_url='https://bookwyrm.social/search?q=', + isbn_search_url='https://bookwyrm.social/isbn/', priority=2, ) @@ -88,6 +90,7 @@ def init_connectors(): books_url='https://openlibrary.org', covers_url='https://covers.openlibrary.org', search_url='https://openlibrary.org/search?q=', + isbn_search_url='https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:', priority=3, ) diff --git a/bookwyrm/migrations/0047_connector_isbn_search_url.py b/bookwyrm/migrations/0047_connector_isbn_search_url.py new file mode 100644 index 000000000..617a89d9d --- /dev/null +++ b/bookwyrm/migrations/0047_connector_isbn_search_url.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2021-02-28 16:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0046_sitesettings_privacy_policy'), + ] + + operations = [ + migrations.AddField( + model_name='connector', + name='isbn_search_url', + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/bookwyrm/models/connector.py b/bookwyrm/models/connector.py index 6f64cdf3e..c1fbf58bc 100644 --- a/bookwyrm/models/connector.py +++ b/bookwyrm/models/connector.py @@ -22,6 +22,7 @@ class Connector(BookWyrmModel): books_url = models.CharField(max_length=255) covers_url = models.CharField(max_length=255) search_url = models.CharField(max_length=255, null=True, blank=True) + isbn_search_url = models.CharField(max_length=255, null=True, blank=True) politeness_delay = models.IntegerField(null=True, blank=True) #seconds max_query_count = models.IntegerField(null=True, blank=True) diff --git a/bookwyrm/templates/isbn_search_results.html b/bookwyrm/templates/isbn_search_results.html new file mode 100644 index 000000000..a3861a68a --- /dev/null +++ b/bookwyrm/templates/isbn_search_results.html @@ -0,0 +1,33 @@ +{% extends 'layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Search Results" %}{% endblock %} + +{% block content %} +{% with book_results|first as local_results %} +
+

{% blocktrans %}Search Results for "{{ query }}"{% endblocktrans %}

+
+ +
+
+

{% trans "Matching Books" %}

+
+ {% if not results %} +

{% blocktrans %}No books found for "{{ query }}"{% endblocktrans %}

+ {% else %} + + {% endif %} +
+ +
+
+
+{% endwith %} +{% endblock %} diff --git a/bookwyrm/tests/connectors/test_abstract_connector.py b/bookwyrm/tests/connectors/test_abstract_connector.py index 6e912858b..1b3821040 100644 --- a/bookwyrm/tests/connectors/test_abstract_connector.py +++ b/bookwyrm/tests/connectors/test_abstract_connector.py @@ -42,6 +42,10 @@ class AbstractConnector(TestCase): return search_result def parse_search_data(self, data): return data + def format_isbn_search_result(self, search_result): + return search_result + def parse_isbn_search_data(self, data): + return data def is_work_data(self, data): return data['type'] == 'work' def get_edition_from_work_data(self, data): diff --git a/bookwyrm/tests/connectors/test_abstract_minimal_connector.py b/bookwyrm/tests/connectors/test_abstract_minimal_connector.py index 0c6d25350..9b939067b 100644 --- a/bookwyrm/tests/connectors/test_abstract_minimal_connector.py +++ b/bookwyrm/tests/connectors/test_abstract_minimal_connector.py @@ -18,6 +18,7 @@ class AbstractConnector(TestCase): books_url='https://example.com/books', covers_url='https://example.com/covers', search_url='https://example.com/search?q=', + isbn_search_url='https://example.com/isbn', ) class TestConnector(abstract_connector.AbstractMinimalConnector): @@ -28,6 +29,10 @@ class AbstractConnector(TestCase): pass def parse_search_data(self, data): return data + def format_isbn_search_result(self, search_result): + return search_result + def parse_isbn_search_data(self, data): + return data self.test_connector = TestConnector('example.com') @@ -39,6 +44,7 @@ class AbstractConnector(TestCase): self.assertEqual(connector.books_url, 'https://example.com/books') self.assertEqual(connector.covers_url, 'https://example.com/covers') self.assertEqual(connector.search_url, 'https://example.com/search?q=') + self.assertEqual(connector.isbn_search_url, 'https://example.com/isbn') self.assertIsNone(connector.name) self.assertEqual(connector.identifier, 'example.com') self.assertIsNone(connector.max_query_count) diff --git a/bookwyrm/tests/connectors/test_openlibrary_connector.py b/bookwyrm/tests/connectors/test_openlibrary_connector.py index 576e353bf..a174300a9 100644 --- a/bookwyrm/tests/connectors/test_openlibrary_connector.py +++ b/bookwyrm/tests/connectors/test_openlibrary_connector.py @@ -27,6 +27,7 @@ class Openlibrary(TestCase): books_url='https://openlibrary.org', covers_url='https://covers.openlibrary.org', search_url='https://openlibrary.org/search?q=', + isbn_search_url='https://openlibrary.org/isbn', ) self.connector = Connector('openlibrary.org') @@ -149,6 +150,34 @@ class Openlibrary(TestCase): self.assertEqual(result.connector, self.connector) + def test_parse_isbn_search_result(self): + ''' extract the results from the search json response ''' + datafile = pathlib.Path(__file__).parent.joinpath( + '../data/ol_isbn_search.json') + search_data = json.loads(datafile.read_bytes()) + result = self.connector.parse_isbn_search_data(search_data) + self.assertIsInstance(result, list) + self.assertEqual(len(result), 1) + + + def test_format_isbn_search_result(self): + ''' translate json from openlibrary into SearchResult ''' + datafile = pathlib.Path(__file__).parent.joinpath( + '../data/ol_isbn_search.json') + search_data = json.loads(datafile.read_bytes()) + results = self.connector.parse_isbn_search_data(search_data) + self.assertIsInstance(results, list) + + result = self.connector.format_isbn_search_result(results[0]) + self.assertIsInstance(result, SearchResult) + self.assertEqual(result.title, 'Les ombres errantes') + self.assertEqual( + result.key, 'https://openlibrary.org/books/OL16262504M') + self.assertEqual(result.author, 'Pascal Quignard') + self.assertEqual(result.year, '2002') + self.assertEqual(result.connector, self.connector) + + @responses.activate def test_load_edition_data(self): ''' format url from key and make request ''' diff --git a/bookwyrm/tests/data/ol_isbn_search.json b/bookwyrm/tests/data/ol_isbn_search.json new file mode 100644 index 000000000..8516ff069 --- /dev/null +++ b/bookwyrm/tests/data/ol_isbn_search.json @@ -0,0 +1,45 @@ +{ + "ISBN:9782070427796": { + "url": "https://openlibrary.org/books/OL16262504M/Les_ombres_errantes", + "key": "/books/OL16262504M", + "title": "Les ombres errantes", + "authors": [ + { + "url": "https://openlibrary.org/authors/OL269675A/Pascal_Quignard", + "name": "Pascal Quignard" + } + ], + "by_statement": "Pascal Quignard.", + "identifiers": { + "goodreads": [ + "1835483" + ], + "librarything": [ + "983474" + ], + "isbn_10": [ + "207042779X" + ], + "openlibrary": [ + "OL16262504M" + ] + }, + "classifications": { + "dewey_decimal_class": [ + "848/.91403" + ] + }, + "publishers": [ + { + "name": "Gallimard" + } + ], + "publish_places": [ + { + "name": "Paris" + } + ], + "publish_date": "2002", + "notes": "Hardback published Grasset, 2002." + } +} diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py new file mode 100644 index 000000000..1966702b4 --- /dev/null +++ b/bookwyrm/tests/views/test_isbn.py @@ -0,0 +1,54 @@ +''' test for app action functionality ''' +import json +from unittest.mock import patch + +from django.http import JsonResponse +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import models, views +from bookwyrm.connectors import abstract_connector +from bookwyrm.settings import DOMAIN + + +class IsbnViews(TestCase): + ''' tag views''' + def setUp(self): + ''' we need basic test data and mocks ''' + self.factory = RequestFactory() + self.local_user = models.User.objects.create_user( + 'mouse@local.com', 'mouse@mouse.com', 'mouseword', + local=True, localname='mouse', + remote_id='https://example.com/users/mouse', + ) + self.work = models.Work.objects.create(title='Test Work') + self.book = models.Edition.objects.create( + title='Test Book', + isbn_13='1234567890123', + remote_id='https://example.com/book/1', + parent_work=self.work + ) + models.Connector.objects.create( + identifier='self', + connector_file='self_connector', + local=True + ) + models.SiteSettings.objects.create() + + + def test_isbn_json_response(self): + ''' searches local data only and returns book data in json format ''' + view = views.Isbn.as_view() + request = self.factory.get('') + with patch('bookwyrm.views.isbn.is_api_request') as is_api: + is_api.return_value = True + response = view(request, isbn='1234567890123') + self.assertIsInstance(response, JsonResponse) + + data = json.loads(response.content) + self.assertEqual(len(data), 1) + self.assertEqual(data[0]['title'], 'Test Book') + self.assertEqual( + data[0]['key'], 'https://%s/book/%d' % (DOMAIN, self.book.id)) + diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index 655b4563a..5d7109e71 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -64,6 +64,10 @@ class ShelfViews(TestCase): pass def parse_search_data(self, data): pass + def format_isbn_search_result(self, search_result): + return search_result + def parse_isbn_search_data(self, data): + return data models.Connector.objects.create( identifier='example.com', connector_file='openlibrary', diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index a741088a2..1c3da3016 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -135,6 +135,9 @@ urlpatterns = [ re_path(r'^resolve-book/?$', views.resolve_book), re_path(r'^switch-edition/?$', views.switch_edition), + # isbn + re_path(r'^isbn/(?P\d+)(.json)?/?$', views.Isbn.as_view()), + # author re_path(r'^author/(?P\d+)(.json)?/?$', views.Author.as_view()), re_path(r'^author/(?P\d+)/edit/?$', views.EditAuthor.as_view()), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 2c7cdc461..dd601b28b 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -31,3 +31,4 @@ from .site import Site from .status import CreateStatus, DeleteStatus from .updates import Updates from .user import User, EditUser, Followers, Following +from .isbn import Isbn diff --git a/bookwyrm/views/isbn.py b/bookwyrm/views/isbn.py new file mode 100644 index 000000000..e5539ba3a --- /dev/null +++ b/bookwyrm/views/isbn.py @@ -0,0 +1,29 @@ +''' isbn search view ''' +from django.http import HttpResponseNotFound +from django.http import JsonResponse +from django.shortcuts import get_object_or_404, redirect +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View +from django.views.decorators.http import require_POST + +from bookwyrm import forms, models +from bookwyrm.connectors import connector_manager +from .helpers import is_api_request + +# pylint: disable= no-self-use +class Isbn(View): + ''' search a book by isbn ''' + def get(self, request, isbn): + ''' info about a book ''' + book_results = connector_manager.isbn_local_search(isbn) + + if is_api_request(request): + return JsonResponse([r.json() for r in book_results], safe=False) + + data = { + 'title': 'ISBN Search Results', + 'results': book_results, + 'query': isbn, + } + return TemplateResponse(request, 'isbn_search_results.html', data) From a52fee4ccfdd400ad07b2c291e8fb53462e8d486 Mon Sep 17 00:00:00 2001 From: Fabien Basmaison Date: Sat, 6 Mar 2021 21:18:39 +0100 Subject: [PATCH 34/58] Remove (potentially useful) unused CSS. --- bookwyrm/static/css/format.css | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/bookwyrm/static/css/format.css b/bookwyrm/static/css/format.css index 9badfaf0b..435d8eb9e 100644 --- a/bookwyrm/static/css/format.css +++ b/bookwyrm/static/css/format.css @@ -161,35 +161,3 @@ html { content: "\e905"; right: 0; } - -/** - * Accessibility (a11y) - ============================================================================ */ - -/** - * Skip links - * - * @see https://webaim.org/styles/main.css - ---------------------------------------------------------------------------- */ -.skip-link { - position: absolute; - opacity: 0; - z-index: 100; - padding: 6px; - border: 1px solid white; - color: white; - background: #BF1722; - transition: opacity 1s ease-out; -} - -.skip-link:focus { - opacity: 1; - outline-color: transparent; - transition: opacity .1s ease-in; -} - -@media (prefers-reduced-motion: reduce) { - .skip-link { - transition-duration: 0.001ms !important; - } -} From 9ed18a2b1d20f5c052d1331e30265fbf1f8e5a4e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 6 Mar 2021 13:11:44 -0800 Subject: [PATCH 35/58] Fixes display name showing up on user page --- bookwyrm/templates/user/user.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/user/user.html b/bookwyrm/templates/user/user.html index cefaab99f..52a915610 100644 --- a/bookwyrm/templates/user/user.html +++ b/bookwyrm/templates/user/user.html @@ -1,7 +1,7 @@ {% extends 'user/user_layout.html' %} {% load i18n %} -{% block title %}{{ user.name }}{% endblock %} +{% block title %}{{ user.display_name }}{% endblock %} {% block header %}
From 09c5275ec41efb0a7467081e24b98668de7a299c Mon Sep 17 00:00:00 2001 From: erion Date: Sun, 7 Mar 2021 13:18:10 +0100 Subject: [PATCH 36/58] Fix typo. --- bookwyrm/templates/feed/status.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/feed/status.html b/bookwyrm/templates/feed/status.html index fc92f8556..9f90f355d 100644 --- a/bookwyrm/templates/feed/status.html +++ b/bookwyrm/templates/feed/status.html @@ -4,7 +4,7 @@ {% block panel %}
- + {% trans "Back" %}
From cb8ec01ccfff8ca71296226aea19f4050a5a12b8 Mon Sep 17 00:00:00 2001 From: erion Date: Sun, 7 Mar 2021 13:55:50 +0100 Subject: [PATCH 37/58] Indicate which page is the current. --- bookwyrm/templates/feed/feed.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bookwyrm/templates/feed/feed.html b/bookwyrm/templates/feed/feed.html index 1eae24d4e..4eb363e4a 100644 --- a/bookwyrm/templates/feed/feed.html +++ b/bookwyrm/templates/feed/feed.html @@ -6,13 +6,13 @@

{% blocktrans %}{{ tab_title }} Timeline{% endblocktrans %}

From ae8d39995d514f62b2a83e1e401f3244dcb7938b Mon Sep 17 00:00:00 2001 From: erion Date: Sun, 7 Mar 2021 14:39:18 +0100 Subject: [PATCH 38/58] Hide avatar image to screen readers on the status pages, since there is a link present for a user already. --- bookwyrm/templates/snippets/avatar.html | 2 +- bookwyrm/templates/snippets/status/status_header.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/snippets/avatar.html b/bookwyrm/templates/snippets/avatar.html index ca49075cf..6d27cd856 100644 --- a/bookwyrm/templates/snippets/avatar.html +++ b/bookwyrm/templates/snippets/avatar.html @@ -1,3 +1,3 @@ {% load bookwyrm_tags %} -{{ user.alt_text }} +{{ user.alt_text }} diff --git a/bookwyrm/templates/snippets/status/status_header.html b/bookwyrm/templates/snippets/status/status_header.html index 2b9418200..a9a8d72c5 100644 --- a/bookwyrm/templates/snippets/status/status_header.html +++ b/bookwyrm/templates/snippets/status/status_header.html @@ -1,6 +1,6 @@ {% load bookwyrm_tags %} {% load i18n %} -{% include 'snippets/avatar.html' with user=status.user %} +{% include 'snippets/avatar.html' with user=status.user ariaHide="true" %} {% include 'snippets/username.html' with user=status.user %} {% if status.status_type == 'GeneratedNote' %} From 9082eefd8fd7073342af5116ac2432b82cb6a28d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 07:08:19 -0800 Subject: [PATCH 39/58] Sets specific proportions for book page columns --- bookwyrm/templates/book.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index d80daca24..ec6c504aa 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -35,7 +35,7 @@
-
+
{% include 'snippets/book_cover.html' with book=book size=large %} {% include 'snippets/rate_action.html' with user=request.user book=book %} {% include 'snippets/shelve_button/shelve_button.html' %} @@ -93,7 +93,7 @@
-
+

{% include 'snippets/stars.html' with rating=rating %} @@ -201,7 +201,7 @@

-
+
{% if book.subjects %}

{% trans "Subjects" %}

From 9c94be8804b3bc7bcdb5c5bfbcb9bba83ffb4972 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 07:35:38 -0800 Subject: [PATCH 40/58] Fixes typo in subject places block --- bookwyrm/templates/book.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index ec6c504aa..c4cede2ed 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -217,7 +217,7 @@

{% trans "Places" %}

    - {% for place in book.subject_placess %} + {% for place in book.subject_places %}
  • {{ place }}
  • {% endfor %}
From e5bdb4b9d1a9ef38ad49227362df28d1d9945099 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 07:35:50 -0800 Subject: [PATCH 41/58] Make empty cover value null --- bookwyrm/activitypub/book.py | 2 +- bookwyrm/tests/actions/__init__.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 bookwyrm/tests/actions/__init__.py diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index 87c40c90a..8c32be967 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -26,7 +26,7 @@ class Book(ActivityObject): librarythingKey: str = '' goodreadsKey: str = '' - cover: Image = field(default_factory=lambda: {}) + cover: Image = None type: str = 'Book' diff --git a/bookwyrm/tests/actions/__init__.py b/bookwyrm/tests/actions/__init__.py deleted file mode 100644 index b6e690fd5..000000000 --- a/bookwyrm/tests/actions/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import * From b895059f03f25a866cffde77d600c8a5cb8f3034 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 07:42:02 -0800 Subject: [PATCH 42/58] Uses same alt text generation for books with no cover --- bookwyrm/templates/snippets/book_cover.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bookwyrm/templates/snippets/book_cover.html b/bookwyrm/templates/snippets/book_cover.html index 6d15b37f8..921378537 100644 --- a/bookwyrm/templates/snippets/book_cover.html +++ b/bookwyrm/templates/snippets/book_cover.html @@ -6,8 +6,7 @@
No cover
-

{{ book.title }}

-

({{ book.edition_info }})

+

{{ book.alt_text }}

{% endif %} From dfecdca6f93bb4f52c4a7ac9f807041fab816495 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 07:56:33 -0800 Subject: [PATCH 43/58] Fixes display of ratings --- bookwyrm/templates/book.html | 4 ++-- bookwyrm/templates/layout.html | 2 +- bookwyrm/templates/snippets/username.html | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index c4cede2ed..06578e894 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -254,8 +254,8 @@
{% include 'snippets/username.html' with user=rating.user %}
-
-
{% trans "rated it" %}
+
+

{% trans "rated it" %}

{% include 'snippets/stars.html' with rating=rating.rating %}
diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index ee42b4f6e..8a708f633 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -79,7 +79,7 @@ aria-controls="navbar-dropdown" > {% include 'snippets/avatar.html' with user=request.user %} - {% include 'snippets/username.html' with user=request.user anchor=false %} + {% include 'snippets/username.html' with user=request.user anchor=false %}
-{% include 'snippets/delete_readthrough_modal.html' with controls_text="delete-readthrough" controls_uid=readthrough.id %} +{% include 'snippets/delete_readthrough_modal.html' with controls_text="delete-readthrough" controls_uid=readthrough.id no_body=True %} From 5ddb3b810e800648d8607026d97bdad611cb4d65 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 08:37:39 -0800 Subject: [PATCH 45/58] Don't show books lists when item isn't approved --- bookwyrm/views/books.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/books.py b/bookwyrm/views/books.py index 4d6afba96..cf246446c 100644 --- a/bookwyrm/views/books.py +++ b/bookwyrm/views/books.py @@ -89,7 +89,7 @@ class Book(View): 'rating': reviews.aggregate(Avg('rating'))['rating__avg'], 'tags': models.UserTag.objects.filter(book=book), 'lists': privacy_filter( - request.user, book.list_set.all() + request.user, book.list_set.filter(listitem__approved=True) ), 'user_tags': user_tags, 'user_shelves': user_shelves, From a70264c12c71b1a08ee86d53da71480cc769c7a1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 08:42:30 -0800 Subject: [PATCH 46/58] Fixes showing link to user lists --- bookwyrm/templates/snippets/status/status_header.html | 2 ++ bookwyrm/templates/user/user_layout.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/snippets/status/status_header.html b/bookwyrm/templates/snippets/status/status_header.html index a9a8d72c5..cecdddf61 100644 --- a/bookwyrm/templates/snippets/status/status_header.html +++ b/bookwyrm/templates/snippets/status/status_header.html @@ -1,7 +1,9 @@ {% load bookwyrm_tags %} {% load i18n %} + {% include 'snippets/avatar.html' with user=status.user ariaHide="true" %} {% include 'snippets/username.html' with user=status.user %} + {% if status.status_type == 'GeneratedNote' %} {{ status.content | safe }} diff --git a/bookwyrm/templates/user/user_layout.html b/bookwyrm/templates/user/user_layout.html index d76291608..75dc61dc3 100644 --- a/bookwyrm/templates/user/user_layout.html +++ b/bookwyrm/templates/user/user_layout.html @@ -56,7 +56,7 @@ {% trans "Reading Goal" %} {% endif %} - {% if is_self or user.lists.exists %} + {% if is_self or user.list_set.exists %} {% url 'user-lists' user|username as url %} {% trans "Lists" %} From ec92aff7930c4f4d2749d939c7c3704ce20fc7fe Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 08:50:07 -0800 Subject: [PATCH 47/58] Clearer notification preview for generated notes --- bookwyrm/templates/notifications.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/notifications.html b/bookwyrm/templates/notifications.html index 007e6b053..d27196ba9 100644 --- a/bookwyrm/templates/notifications.html +++ b/bookwyrm/templates/notifications.html @@ -114,7 +114,9 @@
{% if related_status.content %} - {{ related_status.content | safe | truncatewords_html:10 }} + + {{ related_status.content | safe | truncatewords_html:10 }}{% if related_status.mention_books %} {{ related_status.mention_books.first.title }}{% endif %} + {% elif related_status.quote %} {{ related_status.quote | safe | truncatewords_html:10 }} {% elif related_status.rating %} From c0ccb7065c450f24ea67c2958603ddc90857c8b3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 09:22:35 -0800 Subject: [PATCH 48/58] Safer federation of book data changes Only broadcast to other BW instances, plus bonus error handling --- bookwyrm/models/activitypub_mixin.py | 2 +- bookwyrm/models/book.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index bebe00d02..10015bf14 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -449,7 +449,7 @@ def broadcast_task(sender_id, activity, recipients): for recipient in recipients: try: sign_and_send(sender, activity, recipient) - except (HTTPError, SSLError) as e: + except (HTTPError, SSLError, ConnectionError) as e: logger.exception(e) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 6a1a18b1e..84bfbc6bd 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -37,6 +37,10 @@ class BookDataModel(ObjectMixin, BookWyrmModel): self.remote_id = None return super().save(*args, **kwargs) + def broadcast(self, activity, sender, software='bookwyrm'): + ''' only send book data updates to other bookwyrm instances ''' + super().broadcast(activity, sender, software=software) + class Book(BookDataModel): ''' a generic book, which can mean either an edition or a work ''' From 71bbea83f97ca6cda270180aab940ab882687a7b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 09:42:31 -0800 Subject: [PATCH 49/58] Adds discard check to favs --- bookwyrm/activitypub/base_activity.py | 2 +- bookwyrm/models/favorite.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 57f1a7134..c732fe1d3 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -102,7 +102,7 @@ class ActivityObject: if allow_create and \ hasattr(model, 'ignore_activity') and \ model.ignore_activity(self): - return None + raise ActivitySerializerError() # check for an existing instance instance = instance or model.find_existing(self.serialize()) diff --git a/bookwyrm/models/favorite.py b/bookwyrm/models/favorite.py index f90195016..66befd80c 100644 --- a/bookwyrm/models/favorite.py +++ b/bookwyrm/models/favorite.py @@ -17,6 +17,11 @@ class Favorite(ActivityMixin, BookWyrmModel): activity_serializer = activitypub.Like + @classmethod + def ignore_activity(cls, activity): + ''' don't bother with incoming favs of unknown statuses ''' + return cls.objects.filter(remote_id=activity.object).exists() + def save(self, *args, **kwargs): ''' update user active time ''' self.user.last_active_date = timezone.now() From 09b77e567f8dc886ed4a505a87d79141fbddc8d2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 09:44:42 -0800 Subject: [PATCH 50/58] Check for invalid json before verifying signature --- bookwyrm/views/inbox.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bookwyrm/views/inbox.py b/bookwyrm/views/inbox.py index 4da4e5b6e..46385093c 100644 --- a/bookwyrm/views/inbox.py +++ b/bookwyrm/views/inbox.py @@ -20,7 +20,7 @@ class Inbox(View): ''' requests sent by outside servers''' def post(self, request, username=None): ''' only works as POST request ''' - # first let's do some basic checks to see if this is legible + # make sure the user's inbox even exists if username: try: models.User.objects.get(localname=username) @@ -33,6 +33,11 @@ class Inbox(View): except json.decoder.JSONDecodeError: return HttpResponseBadRequest() + if not 'object' in activity_json or \ + not 'type' in activity_json or \ + not activity_json['type'] in activitypub.activity_objects: + return HttpResponseNotFound() + # verify the signature if not has_valid_signature(request, activity_json): if activity_json['type'] == 'Delete': @@ -42,12 +47,6 @@ class Inbox(View): return HttpResponse() return HttpResponse(status=401) - # just some quick smell tests before we try to parse the json - if not 'object' in activity_json or \ - not 'type' in activity_json or \ - not activity_json['type'] in activitypub.activity_objects: - return HttpResponseNotFound() - activity_task.delay(activity_json) return HttpResponse() @@ -63,7 +62,11 @@ def activity_task(activity_json): # cool that worked, now we should do the action described by the type # (create, update, delete, etc) - activity.action() + try: + activity.action() + except activitypub.ActivitySerializerError: + # this is raised if the activity is discarded + return def has_valid_signature(request, activity): From 47cf77145d19adb1ffc11364a8f45ec948ec8018 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 09:45:02 -0800 Subject: [PATCH 51/58] Updates tests for inbox tweaks --- bookwyrm/models/favorite.py | 2 +- bookwyrm/tests/views/test_inbox.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bookwyrm/models/favorite.py b/bookwyrm/models/favorite.py index 66befd80c..de500e51b 100644 --- a/bookwyrm/models/favorite.py +++ b/bookwyrm/models/favorite.py @@ -20,7 +20,7 @@ class Favorite(ActivityMixin, BookWyrmModel): @classmethod def ignore_activity(cls, activity): ''' don't bother with incoming favs of unknown statuses ''' - return cls.objects.filter(remote_id=activity.object).exists() + return not cls.objects.filter(remote_id=activity.object).exists() def save(self, *args, **kwargs): ''' update user active time ''' diff --git a/bookwyrm/tests/views/test_inbox.py b/bookwyrm/tests/views/test_inbox.py index ff55ad042..b0bd3e42f 100644 --- a/bookwyrm/tests/views/test_inbox.py +++ b/bookwyrm/tests/views/test_inbox.py @@ -74,7 +74,7 @@ class Inbox(TestCase): mock_valid.return_value = False result = self.client.post( '/user/mouse/inbox', - '{"type": "Test", "object": "exists"}', + '{"type": "Announce", "object": "exists"}', content_type="application/json" ) self.assertEqual(result.status_code, 401) @@ -494,6 +494,21 @@ class Inbox(TestCase): self.assertEqual(fav.remote_id, 'https://example.com/fav/1') self.assertEqual(fav.user, self.remote_user) + def test_ignore_favorite(self): + ''' don't try to save an unknown status ''' + activity = { + '@context': 'https://www.w3.org/ns/activitystreams', + 'id': 'https://example.com/fav/1', + 'actor': 'https://example.com/users/rat', + 'type': 'Like', + 'published': 'Mon, 25 May 2020 19:31:20 GMT', + 'object': 'https://unknown.status/not-found', + } + + views.inbox.activity_task(activity) + + self.assertFalse(models.Favorite.objects.exists()) + def test_handle_unfavorite(self): ''' fav a status ''' activity = { From 0bd27928e4d0641738a7fffe0b6d51e73e26b8e7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 7 Mar 2021 10:24:46 -0800 Subject: [PATCH 52/58] Removes username snippet --- bookwyrm/templates/book.html | 2 +- bookwyrm/templates/layout.html | 2 +- bookwyrm/templates/lists/created_text.html | 10 ++++++++++ bookwyrm/templates/lists/curate.html | 2 +- bookwyrm/templates/lists/list_items.html | 5 +++-- bookwyrm/templates/lists/list_layout.html | 5 +++-- bookwyrm/templates/notifications.html | 6 ++++-- bookwyrm/templates/preferences/blocks.html | 2 +- bookwyrm/templates/search_results.html | 6 ++++-- bookwyrm/templates/snippets/status/status.html | 6 ++++-- .../templates/snippets/status/status_header.html | 14 ++++++++++++-- bookwyrm/templates/snippets/username.html | 13 ------------- bookwyrm/templates/user/followers.html | 13 ++++++++----- bookwyrm/templates/user/following.html | 7 +++++-- bookwyrm/templates/user/user_layout.html | 2 +- 15 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 bookwyrm/templates/lists/created_text.html delete mode 100644 bookwyrm/templates/snippets/username.html diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index 06578e894..16bf11972 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -252,7 +252,7 @@
{% include 'snippets/avatar.html' with user=rating.user %}
- {% include 'snippets/username.html' with user=rating.user %} + {{ rating.user.display_name }}

{% trans "rated it" %}

diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 8a708f633..377acb6c5 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -79,7 +79,7 @@ aria-controls="navbar-dropdown" > {% include 'snippets/avatar.html' with user=request.user %} - {% include 'snippets/username.html' with user=request.user anchor=false %} + {{ user.display_name }}