From cef46a1827258176cb2cde277291616c11f2fcdf Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 7 Oct 2021 16:53:39 -0700 Subject: [PATCH 01/69] Adds migration --- bookwyrm/forms.py | 3 + .../migrations/0107_auto_20211007_2253.py | 105 ++++++++++++++++++ bookwyrm/models/__init__.py | 1 + bookwyrm/models/book.py | 2 +- bookwyrm/models/link.py | 1 + bookwyrm/views/__init__.py | 1 - 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 bookwyrm/migrations/0107_auto_20211007_2253.py diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index c112186ae..25429fdac 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -195,6 +195,8 @@ class EditionForm(CustomForm): "shelves", "connector", "search_vector", + "links", + "file_links", ] @@ -207,6 +209,7 @@ class AuthorForm(CustomForm): "created_date", "updated_date", "search_vector", + "links", ] diff --git a/bookwyrm/migrations/0107_auto_20211007_2253.py b/bookwyrm/migrations/0107_auto_20211007_2253.py new file mode 100644 index 000000000..d5690e4fb --- /dev/null +++ b/bookwyrm/migrations/0107_auto_20211007_2253.py @@ -0,0 +1,105 @@ +# Generated by Django 3.2.5 on 2021-10-07 22:53 + +import bookwyrm.models.activitypub_mixin +import bookwyrm.models.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0106_user_preferred_language"), + ] + + operations = [ + migrations.CreateModel( + name="Link", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_date", models.DateTimeField(auto_now_add=True)), + ("updated_date", models.DateTimeField(auto_now=True)), + ( + "remote_id", + bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + ("url", bookwyrm.models.fields.CharField(max_length=255)), + ("name", bookwyrm.models.fields.CharField(max_length=255)), + ], + options={ + "abstract": False, + }, + bases=(bookwyrm.models.activitypub_mixin.CollectionItemMixin, models.Model), + ), + migrations.AlterField( + model_name="user", + name="preferred_language", + field=models.CharField( + blank=True, + choices=[ + ("en-us", "English"), + ("de-de", "Deutsch (German)"), + ("es", "Español (Spanish)"), + ("fr-fr", "Français (French)"), + ("zh-hans", "简体中文 (Simplified Chinese)"), + ("zh-hant", "繁體中文 (Traditional Chinese)"), + ], + max_length=255, + null=True, + ), + ), + migrations.CreateModel( + name="FileLink", + fields=[ + ( + "link_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.link", + ), + ), + ("filetype", bookwyrm.models.fields.CharField(max_length=5)), + ( + "filetype_description", + bookwyrm.models.fields.CharField(max_length=100), + ), + ], + options={ + "abstract": False, + }, + bases=("bookwyrm.link",), + ), + migrations.AddField( + model_name="author", + name="links", + field=bookwyrm.models.fields.ManyToManyField(to="bookwyrm.Link"), + ), + migrations.AddField( + model_name="book", + name="links", + field=bookwyrm.models.fields.ManyToManyField(to="bookwyrm.Link"), + ), + migrations.AddField( + model_name="book", + name="file_links", + field=bookwyrm.models.fields.ManyToManyField( + related_name="editions", to="bookwyrm.FileLink" + ), + ), + ] diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index bffd62b45..6e7db5796 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -4,6 +4,7 @@ import sys from .book import Book, Work, Edition, BookDataModel from .author import Author +from .link import Link, FileLink from .connector import Connector from .shelf import Shelf, ShelfBook diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 97969ccf0..8d0e72d40 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -105,7 +105,7 @@ class Book(BookDataModel): objects = InheritanceManager() field_tracker = FieldTracker(fields=["authors", "title", "subtitle", "cover"]) - file_links = fields.ManyToManyField("FileLink") + file_links = fields.ManyToManyField("FileLink", related_name="editions") if ENABLE_THUMBNAIL_GENERATION: cover_bw_book_xsmall_webp = ImageSpecField( diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 47c65afd4..11ddfbde3 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -3,6 +3,7 @@ from .activitypub_mixin import CollectionItemMixin from .base_model import BookWyrmModel from . import fields + class Link(CollectionItemMixin, BookWyrmModel): """a link to a website""" diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index d664c6ff8..63c5c7686 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -48,7 +48,6 @@ from .isbn import Isbn from .landing import About, Home, Landing from .list import Lists, SavedLists, List, Curate, UserLists from .list import save_list, unsave_list, delete_list -from .link import Link, FileLink from .login import Login, Logout from .notifications import Notifications from .outbox import Outbox From c6bdc34499962bbacb1eb72550a8185a408a2549 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 10:20:00 -0800 Subject: [PATCH 02/69] Updates migration --- ...007_2253.py => 0121_auto_20211215_1818.py} | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) rename bookwyrm/migrations/{0107_auto_20211007_2253.py => 0121_auto_20211215_1818.py} (79%) diff --git a/bookwyrm/migrations/0107_auto_20211007_2253.py b/bookwyrm/migrations/0121_auto_20211215_1818.py similarity index 79% rename from bookwyrm/migrations/0107_auto_20211007_2253.py rename to bookwyrm/migrations/0121_auto_20211215_1818.py index d5690e4fb..8b0221377 100644 --- a/bookwyrm/migrations/0107_auto_20211007_2253.py +++ b/bookwyrm/migrations/0121_auto_20211215_1818.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.5 on 2021-10-07 22:53 +# Generated by Django 3.2.5 on 2021-12-15 18:18 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -9,7 +9,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("bookwyrm", "0106_user_preferred_language"), + ("bookwyrm", "0120_list_embed_key"), ] operations = [ @@ -43,23 +43,6 @@ class Migration(migrations.Migration): }, bases=(bookwyrm.models.activitypub_mixin.CollectionItemMixin, models.Model), ), - migrations.AlterField( - model_name="user", - name="preferred_language", - field=models.CharField( - blank=True, - choices=[ - ("en-us", "English"), - ("de-de", "Deutsch (German)"), - ("es", "Español (Spanish)"), - ("fr-fr", "Français (French)"), - ("zh-hans", "简体中文 (Simplified Chinese)"), - ("zh-hant", "繁體中文 (Traditional Chinese)"), - ], - max_length=255, - null=True, - ), - ), migrations.CreateModel( name="FileLink", fields=[ From 40d1beee203d137a3134e9c88409afea34a9a12d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 10:56:49 -0800 Subject: [PATCH 03/69] Adds links to activitypub spec --- bookwyrm/activitypub/book.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index d8599c4b3..2238e3a87 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -17,6 +17,8 @@ class BookData(ActivityObject): goodreadsKey: str = None bnfId: str = None lastEditedBy: str = None + links: List[str] = field(default_factory=lambda: []) + fileLinks: List[str] = field(default_factory=lambda: []) # pylint: disable=invalid-name From 1d6b200172e7fcf0648a83cedf311c5fe930dda8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 12:40:01 -0800 Subject: [PATCH 04/69] Modal to add link --- bookwyrm/templates/book/book.html | 19 +++++++++- bookwyrm/templates/book/file_links_modal.html | 37 +++++++++++++++++++ bookwyrm/views/__init__.py | 8 +++- bookwyrm/views/books/books.py | 22 ++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 bookwyrm/templates/book/file_links_modal.html diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 27d061a28..64daf3fa6 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -147,7 +147,7 @@ {% include 'snippets/toggle/open_button.html' with text=button_text controls_text="add_description" controls_uid=book.id focus="id_description" hide_active=True id="hide_description" %} diff --git a/bookwyrm/templates/book/file_links_modal.html b/bookwyrm/templates/book/file_links_modal.html new file mode 100644 index 000000000..a2f8d0cd6 --- /dev/null +++ b/bookwyrm/templates/book/file_links_modal.html @@ -0,0 +1,37 @@ +{% extends 'components/modal.html' %} +{% load i18n %} + +{% block modal-title %} +{% trans "Add file link" %} +{% endblock %} + +{% block modal-form-open %} + +{% endblock %} + +{% block modal-body %} +{% csrf_token %} +
+ + {{ file_link_form.name }} +
+ +
+
+ + +
+
+ + +
+
+ +{% endblock %} + +{% block modal-footer %} + +{% trans "Cancel" as button_text %} +{% include 'snippets/toggle/toggle_button.html' with text=button_text %} +{% endblock %} +{% block modal-form-close %}{% endblock %} diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index fb9db2105..71c300f7f 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -28,7 +28,13 @@ from .preferences.delete_user import DeleteUser from .preferences.block import Block, unblock # books -from .books.books import Book, upload_cover, add_description, resolve_book +from .books.books import ( + Book, + upload_cover, + add_description, + resolve_book, + add_file_link, +) from .books.books import update_book_from_remote from .books.edit_book import EditBook, ConfirmEditBook from .books.editions import Editions, switch_edition diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index 2d49ae30c..8edeffb3b 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -4,6 +4,7 @@ from uuid import uuid4 from django.contrib.auth.decorators import login_required, permission_required from django.core.files.base import ContentFile from django.core.paginator import Paginator +from django.db import transaction from django.db.models import Avg, Q from django.http import Http404 from django.shortcuts import get_object_or_404, redirect @@ -40,7 +41,7 @@ class Book(View): .filter(Q(id=book_id) | Q(parent_work__id=book_id)) .order_by("-edition_rank") .select_related("parent_work") - .prefetch_related("authors") + .prefetch_related("authors", "file_links") .first() ) @@ -84,6 +85,7 @@ class Book(View): } if request.user.is_authenticated: + data["file_link_form"] = forms.FileLinkForm() readthroughs = models.ReadThrough.objects.filter( user=request.user, book=book, @@ -194,3 +196,21 @@ def update_book_from_remote(request, book_id, connector_identifier): connector.update_book_from_remote(book) return redirect("book", book.id) + + +@login_required +@require_POST +@permission_required("bookwyrm.edit_book", raise_exception=True) +@transaction.atomic +def add_file_link(request, book_id): + """Add a link to a copy of the book you can read""" + book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) + form = forms.FileLinkForm(request.POST) + if not form.is_valid(): + return redirect("book", book.id) + + link = form.save() + book.file_links.add(link) + book.last_edited_by = request.user + book.save() + return redirect("book", book.id) From 4f576b77a0073abcfe41b1934cdb6303ed1be53f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 12:40:31 -0800 Subject: [PATCH 05/69] Use urlfield --- bookwyrm/forms.py | 6 ++++++ ...20211215_1818.py => 0121_auto_20211215_2038.py} | 10 +++------- bookwyrm/models/fields.py | 4 ++++ bookwyrm/models/link.py | 14 ++++++++++---- bookwyrm/templates/book/book.html | 5 ++++- bookwyrm/templates/book/file_links_modal.html | 2 +- bookwyrm/urls.py | 9 ++++++++- 7 files changed, 36 insertions(+), 14 deletions(-) rename bookwyrm/migrations/{0121_auto_20211215_1818.py => 0121_auto_20211215_2038.py} (87%) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 05a6ce918..8c3785f8f 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -216,6 +216,12 @@ class CoverForm(CustomForm): help_texts = {f: None for f in fields} +class FileLinkForm(CustomForm): + class Meta: + model = models.FileLink + exclude = ["remote_id"] + + class EditionForm(CustomForm): class Meta: model = models.Edition diff --git a/bookwyrm/migrations/0121_auto_20211215_1818.py b/bookwyrm/migrations/0121_auto_20211215_2038.py similarity index 87% rename from bookwyrm/migrations/0121_auto_20211215_1818.py rename to bookwyrm/migrations/0121_auto_20211215_2038.py index 8b0221377..d55cb5fdd 100644 --- a/bookwyrm/migrations/0121_auto_20211215_1818.py +++ b/bookwyrm/migrations/0121_auto_20211215_2038.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.5 on 2021-12-15 18:18 +# Generated by Django 3.2.5 on 2021-12-15 20:38 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -35,13 +35,13 @@ class Migration(migrations.Migration): validators=[bookwyrm.models.fields.validate_remote_id], ), ), - ("url", bookwyrm.models.fields.CharField(max_length=255)), + ("url", bookwyrm.models.fields.URLField(max_length=255)), ("name", bookwyrm.models.fields.CharField(max_length=255)), ], options={ "abstract": False, }, - bases=(bookwyrm.models.activitypub_mixin.CollectionItemMixin, models.Model), + bases=(bookwyrm.models.activitypub_mixin.ActivitypubMixin, models.Model), ), migrations.CreateModel( name="FileLink", @@ -58,10 +58,6 @@ class Migration(migrations.Migration): ), ), ("filetype", bookwyrm.models.fields.CharField(max_length=5)), - ( - "filetype_description", - bookwyrm.models.fields.CharField(max_length=100), - ), ], options={ "abstract": False, diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 7d14f88f9..397bced59 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -516,6 +516,10 @@ class CharField(ActivitypubFieldMixin, models.CharField): """activitypub-aware char field""" +class URLField(ActivitypubFieldMixin, models.URLField): + """activitypub-aware url field""" + + class TextField(ActivitypubFieldMixin, models.TextField): """activitypub-aware text field""" diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 11ddfbde3..0a46c59c2 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -1,18 +1,24 @@ """ outlink data """ -from .activitypub_mixin import CollectionItemMixin +from .activitypub_mixin import ActivitypubMixin from .base_model import BookWyrmModel from . import fields -class Link(CollectionItemMixin, BookWyrmModel): +class Link(ActivitypubMixin, BookWyrmModel): """a link to a website""" - url = fields.CharField(max_length=255) + url = fields.URLField(max_length=255) name = fields.CharField(max_length=255) + def save(self, *args, **kwargs): + """create a link""" + # this is never broadcast, the owning model broadcasts an update + if "broadcast" in kwargs: + del kwargs["broadcast"] + return super().save(*args, **kwargs) + class FileLink(Link): """a link to a file""" filetype = fields.CharField(max_length=5) - filetype_description = fields.CharField(max_length=100) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 64daf3fa6..6b96856a0 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -351,7 +351,10 @@ {% if book.file_links %} {% endif %} diff --git a/bookwyrm/templates/book/file_links_modal.html b/bookwyrm/templates/book/file_links_modal.html index a2f8d0cd6..5aca941c5 100644 --- a/bookwyrm/templates/book/file_links_modal.html +++ b/bookwyrm/templates/book/file_links_modal.html @@ -19,7 +19,7 @@
- +
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 2829d2034..8ddf56e96 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -427,7 +427,14 @@ urlpatterns = [ re_path( r"^upload-cover/(?P\d+)/?$", views.upload_cover, name="upload-cover" ), - re_path(r"^add-description/(?P\d+)/?$", views.add_description), + re_path( + r"^add-description/(?P\d+)/?$", + views.add_description, + name="add-description", + ), + re_path( + r"^add-file-link/(?P\d+)/?$", views.add_file_link, name="add-file-link" + ), re_path(r"^resolve-book/?$", views.resolve_book, name="resolve-book"), re_path(r"^switch-edition/?$", views.switch_edition, name="switch-edition"), re_path( From cc3db31db9b53afc4522d9201c5cf0f628dfbf0b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:11:49 -0800 Subject: [PATCH 06/69] Adds noscript fallback for links modal --- bookwyrm/templates/book/book.html | 5 +++-- ...e_links_modal.html => file_link_modal.html} | 4 ++-- bookwyrm/templates/book/file_link_page.html | 10 ++++++++++ bookwyrm/urls.py | 7 ++++++- bookwyrm/views/__init__.py | 2 +- bookwyrm/views/books/books.py | 18 ------------------ 6 files changed, 22 insertions(+), 24 deletions(-) rename bookwyrm/templates/book/{file_links_modal.html => file_link_modal.html} (88%) create mode 100644 bookwyrm/templates/book/file_link_page.html diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 6b96856a0..99bf8d70d 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -361,8 +361,9 @@ {% if can_edit_book %} {% trans "Add link to copy" as button_text %} - {% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="edit_file_links" controls_uid=book.id focus="modal_title_edit_file_links" class="is-small" icon_with_text="plus" %} - {% include 'book/file_links_modal.html' with book=book controls_text="edit_file_links" controls_uid=book.id %} + {% url 'file-link' book.id as fallback_url %} + {% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="edit_file_links" controls_uid=book.id focus="modal_title_edit_file_links" class="is-small" icon_with_text="plus" fallback_url=fallback_url %} + {% include 'book/file_link_modal.html' with book=book controls_text="edit_file_links" controls_uid=book.id %} {% endif %}
diff --git a/bookwyrm/templates/book/file_links_modal.html b/bookwyrm/templates/book/file_link_modal.html similarity index 88% rename from bookwyrm/templates/book/file_links_modal.html rename to bookwyrm/templates/book/file_link_modal.html index 5aca941c5..3870eb8e6 100644 --- a/bookwyrm/templates/book/file_links_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -6,13 +6,13 @@ {% endblock %} {% block modal-form-open %} -
+ {% endblock %} {% block modal-body %} {% csrf_token %}
- + {{ file_link_form.name }}
diff --git a/bookwyrm/templates/book/file_link_page.html b/bookwyrm/templates/book/file_link_page.html new file mode 100644 index 000000000..ba1e61d0f --- /dev/null +++ b/bookwyrm/templates/book/file_link_page.html @@ -0,0 +1,10 @@ +{% extends 'layout.html' %} +{% load i18n %} + +{% block title %} +{% trans "File Links" %} +{% endblock %} + +{% block content %} +{% include "book/file_link_modal.html" with book=book active=True static=True %} +{% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 8ddf56e96..423094e3d 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -433,7 +433,12 @@ urlpatterns = [ name="add-description", ), re_path( - r"^add-file-link/(?P\d+)/?$", views.add_file_link, name="add-file-link" + rf"{BOOK_PATH}/file-link/?$", views.FileLink.as_view(), name="file-link" + ), + re_path( + rf"{BOOK_PATH}/file-link/(?P\d+)/?$", + views.FileLink.as_view(), + name="file-link" ), re_path(r"^resolve-book/?$", views.resolve_book, name="resolve-book"), re_path(r"^switch-edition/?$", views.switch_edition, name="switch-edition"), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 71c300f7f..b1de67be7 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -33,11 +33,11 @@ from .books.books import ( upload_cover, add_description, resolve_book, - add_file_link, ) from .books.books import update_book_from_remote from .books.edit_book import EditBook, ConfirmEditBook from .books.editions import Editions, switch_edition +from .books.links import FileLink # landing from .landing.landing import About, Home, Landing diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index 8edeffb3b..405a67c60 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -196,21 +196,3 @@ def update_book_from_remote(request, book_id, connector_identifier): connector.update_book_from_remote(book) return redirect("book", book.id) - - -@login_required -@require_POST -@permission_required("bookwyrm.edit_book", raise_exception=True) -@transaction.atomic -def add_file_link(request, book_id): - """Add a link to a copy of the book you can read""" - book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) - form = forms.FileLinkForm(request.POST) - if not form.is_valid(): - return redirect("book", book.id) - - link = form.save() - book.file_links.add(link) - book.last_edited_by = request.user - book.save() - return redirect("book", book.id) From dcf5694b663b768758c5ffc581719d7e05064ed3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:15:51 -0800 Subject: [PATCH 07/69] Use class view --- bookwyrm/views/books/links.py | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 bookwyrm/views/books/links.py diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py new file mode 100644 index 000000000..722d0545a --- /dev/null +++ b/bookwyrm/views/books/links.py @@ -0,0 +1,43 @@ +""" the good stuff! the books! """ +from django.contrib.auth.decorators import login_required, permission_required +from django.db import transaction +from django.shortcuts import get_object_or_404, redirect +from django.template.response import TemplateResponse +from django.views import View +from django.utils.decorators import method_decorator + +from bookwyrm import forms, models + + +# pylint: disable=no-self-use +@method_decorator(login_required, name="dispatch") +@method_decorator( + permission_required("bookwyrm.edit_book", raise_exception=True), name="dispatch" +) +class FileLink(View): + """a book! this is the stuff""" + + def get(self, request, book_id, link_id=None): + """info about a book""" + book = get_object_or_404(models.Edition, id=book_id) + link = get_object_or_404(models.FileLink, id=link_id) if link_id else None + data = { + "file_link_form": forms.FileLinkForm(instance=link), + "book": book, + } + return TemplateResponse(request, "book/file_link_page.html", data) + + @transaction.atomic + def post(self, request, book_id): + """Add a link to a copy of the book you can read""" + book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) + form = forms.FileLinkForm(request.POST) + if not form.is_valid(): + data = {"file_link_form": form, "book": book} + return TemplateResponse(request, "book/file_link_page.html", data) + + link = form.save() + book.file_links.add(link) + book.last_edited_by = request.user + book.save() + return redirect("book", book.id) From c8e038cd4e7fa3dffcce4a4f7011de86f4a69c42 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:20:05 -0800 Subject: [PATCH 08/69] Adds form errors --- bookwyrm/templates/book/file_link_modal.html | 5 ++++- bookwyrm/views/books/links.py | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 3870eb8e6..5ffe8ce80 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -14,16 +14,19 @@
{{ file_link_form.name }} + {% include 'snippets/form_errors.html' with errors_list=file_link_form.name.errors id="desc_name" %}
- + + {% include 'snippets/form_errors.html' with errors_list=file_link_form.url.errors id="desc_url" %}
+ {% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index 722d0545a..949c807f5 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -28,10 +28,11 @@ class FileLink(View): return TemplateResponse(request, "book/file_link_page.html", data) @transaction.atomic - def post(self, request, book_id): + def post(self, request, book_id, link_id=None): """Add a link to a copy of the book you can read""" book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) - form = forms.FileLinkForm(request.POST) + link = get_object_or_404(models.FileLink, id=link_id) if link_id else None + form = forms.FileLinkForm(request.POST, instance=link) if not form.is_valid(): data = {"file_link_form": form, "book": book} return TemplateResponse(request, "book/file_link_page.html", data) From 5ed5d5d2227408bdeb82fbbc01c0a99d36b5c60f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:21:08 -0800 Subject: [PATCH 09/69] Don't show cancel button in static mode --- bookwyrm/templates/book/file_link_modal.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 5ffe8ce80..bb20960a6 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -34,7 +34,10 @@ {% block modal-footer %} -{% trans "Cancel" as button_text %} -{% include 'snippets/toggle/toggle_button.html' with text=button_text %} +{% if not static %} + {% trans "Cancel" as button_text %} + {% include 'snippets/toggle/toggle_button.html' with text=button_text %} +{% endif %} + {% endblock %} {% block modal-form-close %}{% endblock %} From d911e2c6db1cf8c7f8dec5b081aa533be483c650 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:23:25 -0800 Subject: [PATCH 10/69] Cleans up sidebar html --- bookwyrm/templates/book/book.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 99bf8d70d..651f7b841 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -320,7 +320,7 @@

{% trans "Lists" %}

@@ -346,7 +346,7 @@ {% endif %} -
+

{% trans "Get a copy" %}

{% if book.file_links %}
    From 322bb909fc5181c058ad06f9aab8299eef0f0f5e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 13:35:10 -0800 Subject: [PATCH 11/69] Better mobile display --- bookwyrm/templates/book/book.html | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 651f7b841..b42648a71 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -291,7 +291,7 @@
-
+
{% if book.subjects %}

{% trans "Subjects" %}

@@ -316,7 +316,7 @@ {% endif %} {% if lists.exists or request.user.list_set.exists %} -
+

{% trans "Lists" %}

    {% for list in lists %} @@ -330,7 +330,7 @@
    -
    +
    {{ file_link_form.name }} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index ee7b2b03c..c73436b06 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -432,9 +432,9 @@ urlpatterns = [ views.add_description, name="add-description", ), - re_path(rf"{BOOK_PATH}/file-link/?$", views.FileLink.as_view(), name="file-link"), + re_path(rf"{BOOK_PATH}/filelink/?$", views.FileLink.as_view(), name="file-link"), re_path( - rf"{BOOK_PATH}/file-link/(?P\d+)/?$", + rf"{BOOK_PATH}/filelink/(?P\d+)/?$", views.FileLink.as_view(), name="file-link", ), diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index 949c807f5..1b6818bae 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -7,6 +7,7 @@ from django.views import View from django.utils.decorators import method_decorator from bookwyrm import forms, models +from bookwyrm.activitypub import ActivitypubResponse # pylint: disable=no-self-use @@ -17,10 +18,13 @@ from bookwyrm import forms, models class FileLink(View): """a book! this is the stuff""" - def get(self, request, book_id, link_id=None): + def get(self, request, book_id=None, link_id=None): """info about a book""" - book = get_object_or_404(models.Edition, id=book_id) link = get_object_or_404(models.FileLink, id=link_id) if link_id else None + if not book_id: + return ActivitypubResponse(link.to_activity()) + + book = get_object_or_404(models.Edition, id=book_id) data = { "file_link_form": forms.FileLinkForm(instance=link), "book": book, From 5c99f142f9cf58f639c0bcbab95a3f01d3436942 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 17:10:59 -0800 Subject: [PATCH 15/69] Serialize links for books --- bookwyrm/activitypub/base_activity.py | 48 ++++++++++++++++----------- bookwyrm/activitypub/person.py | 5 +++ bookwyrm/models/book.py | 7 +++- bookwyrm/models/link.py | 6 +++- bookwyrm/models/user.py | 9 +---- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 7429dbe67..f1b3ad181 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -20,23 +20,6 @@ class ActivityEncoder(JSONEncoder): return o.__dict__ -@dataclass -class Link: - """for tagging a book in a status""" - - href: str - name: str - mediaType: str = None - type: str = "Link" - - -@dataclass -class Mention(Link): - """a subtype of Link for mentioning an actor""" - - type: str = "Mention" - - @dataclass # pylint: disable=invalid-name class Signature: @@ -199,8 +182,9 @@ class ActivityObject: ) return instance - def serialize(self): + def serialize(self, **kwargs): """convert to dictionary with context attr""" + omit = kwargs.get("omit", ()) data = self.__dict__.copy() # recursively serialize for (k, v) in data.items(): @@ -209,8 +193,9 @@ class ActivityObject: data[k] = v.serialize() except TypeError: pass - data = {k: v for (k, v) in data.items() if v is not None} - data["@context"] = "https://www.w3.org/ns/activitystreams" + data = {k: v for (k, v) in data.items() if v is not None and k not in omit} + if "@context" not in omit: + data["@context"] = "https://www.w3.org/ns/activitystreams" return data @@ -305,3 +290,26 @@ def resolve_remote_id( # if we're refreshing, "result" will be set and we'll update it return item.to_model(model=model, instance=result, save=save) + + +@dataclass(init=False) +class Link(ActivityObject): + """for tagging a book in a status""" + + href: str + name: str + mediaType: str = None + id: str = None + type: str = "Link" + + def serialize(self, **kwargs): + """remove fields""" + omit = ("id", "type", "@context") + return super().serialize(omit=omit) + + +@dataclass(init=False) +class Mention(Link): + """a subtype of Link for mentioning an actor""" + + type: str = "Mention" diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 174ead616..576e7f9a6 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -15,6 +15,11 @@ class PublicKey(ActivityObject): publicKeyPem: str type: str = "PublicKey" + def serialize(self, **kwargs): + """remove fields""" + omit = ("type", "@context") + return super().serialize(omit=omit) + # pylint: disable=invalid-name @dataclass(init=False) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index cb811a124..c850f78bd 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -234,7 +234,10 @@ class Work(OrderedCollectionPageMixin, Book): ) activity_serializer = activitypub.Work - serialize_reverse_fields = [("editions", "editions", "-edition_rank")] + serialize_reverse_fields = [ + ("editions", "editions", "-edition_rank"), + ("file_links", "fileLinks", "-created_date"), + ] deserialize_reverse_fields = [("editions", "editions"), ("file_links", "fileLinks")] @@ -289,6 +292,8 @@ class Edition(Book): activity_serializer = activitypub.Edition name_field = "title" + serialize_reverse_fields = [("file_links", "fileLinks", "-created_date")] + deserialize_reverse_fields = [("file_links", "fileLinks")] def get_rank(self): """calculate how complete the data is on this edition""" diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 9c0d32222..8693775b5 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -23,11 +23,15 @@ class Link(ActivitypubMixin, BookWyrmModel): del kwargs["broadcast"] return super().save(*args, **kwargs) + def to_activity(self, omit=(), **kwargs): + """we don't need ALL the fields""" + return super().to_activity(omit=("@context", "id"), **kwargs) + class FileLink(Link): """a link to a file""" - book = fields.ForeignKey( + book = models.ForeignKey( "Book", on_delete=models.CASCADE, related_name="file_links", null=True ) filetype = fields.CharField(max_length=5, activitypub_field="mediaType") diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 4d98f5c57..e13ccd038 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -344,6 +344,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): def delete(self, *args, **kwargs): """deactivate rather than delete a user""" + # pylint: disable=attribute-defined-outside-init self.is_active = False # skip the logic in this class's save() super().save(*args, **kwargs) @@ -404,14 +405,6 @@ class KeyPair(ActivitypubMixin, BookWyrmModel): self.private_key, self.public_key = create_key_pair() return super().save(*args, **kwargs) - def to_activity(self, **kwargs): - """override default AP serializer to add context object - idk if this is the best way to go about this""" - activity_object = super().to_activity(**kwargs) - del activity_object["@context"] - del activity_object["type"] - return activity_object - class AnnualGoal(BookWyrmModel): """set a goal for how many books you read in a year""" From 0629fce17162880410b50f15a269809e6adbfa41 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 15 Dec 2021 17:25:20 -0800 Subject: [PATCH 16/69] Fixes post test --- bookwyrm/tests/views/books/test_links.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index b6363848f..136a76066 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -66,6 +66,7 @@ class LinkViews(TestCase): form.data["name"] = "hi" form.data["url"] = "https://www.example.com" form.data["filetype"] = "HTML" + form.data["book"] = self.book.id request = self.factory.post("", form.data) request.user = self.local_user From 2f47284c775dcc93283d371538e3bcac47d5225d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 09:12:00 -0800 Subject: [PATCH 17/69] Removes outdated code --- bookwyrm/forms.py | 2 +- bookwyrm/models/link.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 8c3785f8f..f031d85a5 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -219,7 +219,7 @@ class CoverForm(CustomForm): class FileLinkForm(CustomForm): class Meta: model = models.FileLink - exclude = ["remote_id"] + exclude = ["remote_id", "filetype"] class EditionForm(CustomForm): diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 8693775b5..bc8f5ce3c 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -23,10 +23,6 @@ class Link(ActivitypubMixin, BookWyrmModel): del kwargs["broadcast"] return super().save(*args, **kwargs) - def to_activity(self, omit=(), **kwargs): - """we don't need ALL the fields""" - return super().to_activity(omit=("@context", "id"), **kwargs) - class FileLink(Link): """a link to a file""" From 400417c79f97600d25076e3e474d17ace2f918f6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:15:32 -0800 Subject: [PATCH 18/69] Fixes form --- bookwyrm/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index f031d85a5..8c3785f8f 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -219,7 +219,7 @@ class CoverForm(CustomForm): class FileLinkForm(CustomForm): class Meta: model = models.FileLink - exclude = ["remote_id", "filetype"] + exclude = ["remote_id"] class EditionForm(CustomForm): From 5d47f339725749698f3932c220067bf96bcaa17f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:29:08 -0800 Subject: [PATCH 19/69] Tick version number --- bookwyrm/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index e95ff96e2..5ea3b2c63 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ env = Env() env.read_env() DOMAIN = env("DOMAIN") -VERSION = "0.1.0" +VERSION = "0.1.1" PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") From e2d1c987b544e538f2dcdfe7ba897b792b1b7711 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 27 Dec 2021 12:41:27 -0800 Subject: [PATCH 20/69] Adds autocomplete scrip --- bookwyrm/static/js/autocomplete.js | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 bookwyrm/static/js/autocomplete.js diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js new file mode 100644 index 000000000..f75948078 --- /dev/null +++ b/bookwyrm/static/js/autocomplete.js @@ -0,0 +1,104 @@ +(function() { + 'use strict'; + + /** + * Suggest a completion as a user types + * + * Use `data-autocomplete=""`on the input field. + * specifying the trie to be used for autocomplete + * + * @example + * + * @param {Event} event + * @return {undefined} + */ + function autocomplete(event) { + const input = event.target; + + // Get suggestions + let suggestions = getSuggestions(input.value, mimetypeTrie); + + const boxId = input.id + "_suggestions"; + + // Create suggestion box, if needed + let suggestionsBox = document.getElementById(boxId); + + if (!suggestionsBox) { + suggestionsBox = document.createElement("ul"); + suggestionsBox.id = boxId; + suggestionsBox.classList.add("autocomplete-suggestions", "box"); + + input.insertAdjacentElement("afterend", suggestionsBox); + } + + // Clear existing suggestions + suggestionsBox.innerHTML = ""; + + // Populate suggestions box + suggestions.forEach(suggestion => { + const suggestionItem = document.createElement("li"); + + suggestionItem.textContent = suggestion; + suggestionsBox.appendChild(suggestionItem); + }); + } + + function getSuggestions(input, trie) { + // Follow the trie through the provided input + input.split("").forEach(letter => { + trie = trie[letter]; + + if (!trie) { + return; + } + }); + + if (!trie) { + return []; + } + + return searchTrie(input, trie); + } + + function searchTrie(output, trie) { + const options = Object.keys(trie); + + if (!options.length) { + return [output]; + } + + return options.map(option => { + const newTrie = trie[option]; + + if (!newTrie) { + return; + } + + return searchTrie(output + option, trie[option]); + }).reduce((prev, next) => prev.concat(next)); + } + + document + .querySelectorAll('[data-autocomplete]') + .forEach(input => { + input.addEventListener('input', autocomplete); + }); +})(); + +const mimetypeTrie = { + "p": { + "d": { + "f": { + "": {}, + "x": {}, + }, + }, + "n": { + "g": {} + }, + } +}; + From 3d07618b5fad61b44cad8b9a89055fe6ae45e9ce Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 27 Dec 2021 12:42:11 -0800 Subject: [PATCH 21/69] Styling for autocomplete box --- bookwyrm/static/css/bookwyrm.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index f385e6295..c98355c3e 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -410,6 +410,13 @@ summary::marker { right: 1em; } +/** Autocomplete suggestions + ******************************************************************************/ +.autocomplete-suggestions { + position: fixed; + z-index: 1; +} + /** Tooltips ******************************************************************************/ From 76694bb89127bae4aafaf422c2b8c407bb80f55d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 27 Dec 2021 12:42:24 -0800 Subject: [PATCH 22/69] Demo for file type --- bookwyrm/templates/book/file_link_modal.html | 3 ++- bookwyrm/templates/layout.html | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 6896fba81..87bda1a15 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -1,5 +1,6 @@ {% extends 'components/modal.html' %} {% load i18n %} +{% load static %} {% block modal-title %} {% trans "Add file link" %} @@ -26,7 +27,7 @@
    - + {% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
    diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 25aaf1b6b..e41f661fe 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -265,6 +265,7 @@ + {% block scripts %}{% endblock %} From bae355e8d2524825e6dba4be9f27ae85e9dd7c31 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 13:19:29 -0800 Subject: [PATCH 23/69] Adds link domain table --- ...nk.py => 0126_filelink_link_linkdomain.py} | 48 +++++++++++++++++-- bookwyrm/models/link.py | 23 ++++++++- 2 files changed, 66 insertions(+), 5 deletions(-) rename bookwyrm/migrations/{0121_filelink_link.py => 0126_filelink_link_linkdomain.py} (58%) diff --git a/bookwyrm/migrations/0121_filelink_link.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py similarity index 58% rename from bookwyrm/migrations/0121_filelink_link.py rename to bookwyrm/migrations/0126_filelink_link_linkdomain.py index 716d56040..1235e81dc 100644 --- a/bookwyrm/migrations/0121_filelink_link.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.5 on 2021-12-16 00:20 +# Generated by Django 3.2.10 on 2022-01-09 21:16 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -9,7 +9,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("bookwyrm", "0120_list_embed_key"), + ("bookwyrm", "0125_alter_user_preferred_language"), ] operations = [ @@ -36,13 +36,53 @@ class Migration(migrations.Migration): ), ), ("url", bookwyrm.models.fields.URLField(max_length=255)), - ("name", bookwyrm.models.fields.CharField(max_length=255)), ], options={ "abstract": False, }, bases=(bookwyrm.models.activitypub_mixin.ActivitypubMixin, models.Model), ), + migrations.CreateModel( + name="LinkDomain", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_date", models.DateTimeField(auto_now_add=True)), + ("updated_date", models.DateTimeField(auto_now=True)), + ( + "remote_id", + bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + ("domain", models.CharField(max_length=255)), + ( + "status", + models.CharField( + choices=[ + ("approved", "Approved"), + ("blocked", "Blocked"), + ("pending", "Pending"), + ], + default="pending", + max_length=50, + ), + ), + ("name", models.CharField(max_length=100)), + ], + options={ + "abstract": False, + }, + ), migrations.CreateModel( name="FileLink", fields=[ @@ -60,7 +100,7 @@ class Migration(migrations.Migration): ("filetype", bookwyrm.models.fields.CharField(max_length=5)), ( "book", - bookwyrm.models.fields.ForeignKey( + models.ForeignKey( null=True, on_delete=django.db.models.deletion.CASCADE, related_name="file_links", diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index bc8f5ce3c..12a5fae19 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -1,5 +1,6 @@ """ outlink data """ from django.db import models +from django.utils.translation import gettext_lazy as _ from bookwyrm import activitypub from .activitypub_mixin import ActivitypubMixin @@ -11,7 +12,6 @@ class Link(ActivitypubMixin, BookWyrmModel): """a link to a website""" url = fields.URLField(max_length=255, activitypub_field="href") - name = fields.CharField(max_length=255) activity_serializer = activitypub.Link reverse_unfurl = True @@ -31,3 +31,24 @@ class FileLink(Link): "Book", on_delete=models.CASCADE, related_name="file_links", null=True ) filetype = fields.CharField(max_length=5, activitypub_field="mediaType") + + +StatusChoices = [ + ("approved", _("Approved")), + ("blocked", _("Blocked")), + ("pending", _("Pending")), +] + + +class LinkDomain(BookWyrmModel): + """List of domains used in links""" + + domain = models.CharField(max_length=255) + status = models.CharField(max_length=50, choices=StatusChoices, default="pending") + name = models.CharField(max_length=100) + + def save(self, *args, **kwargs): + """set a default name""" + if not self.name: + self.name = self.domain + super().save(*args, **kwargs) From bae01e1ea59aaf9541b115c5087db6399a7b8d38 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 13:27:47 -0800 Subject: [PATCH 24/69] Updates modal --- bookwyrm/templates/book/book.html | 11 ++++++++--- bookwyrm/templates/book/file_link_modal.html | 12 +++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 774b2b653..6467bb71a 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -389,9 +389,14 @@
    {% if can_edit_book %}
    - {% trans "Add link to copy" as button_text %} {% url 'file-link' book.id as fallback_url %} - {% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="edit_file_links" controls_uid=book.id focus="modal_title_edit_file_links" class="is-small" icon="plus" fallback_url=fallback_url %} +
    {% endif %} @@ -407,7 +412,7 @@ {% endif %} {% if can_edit_book %} - {% include 'book/file_link_modal.html' with book=book controls_text="edit_file_links" controls_uid=book.id %} + {% include 'book/file_link_modal.html' with book=book id="edit-links" %} {% endif %}
diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 6896fba81..04e215574 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -12,11 +12,10 @@ {% block modal-body %} {% csrf_token %} -
- - {{ file_link_form.name }} - {% include 'snippets/form_errors.html' with errors_list=file_link_form.name.errors id="desc_name" %} -
+ +

+ {% trans "Links from unknown domains will need to be approved by a moderator before they are added." %} +

@@ -36,8 +35,7 @@ {% block modal-footer %} {% if not static %} - {% trans "Cancel" as button_text %} - {% include 'snippets/toggle/toggle_button.html' with text=button_text %} + {% endif %} {% endblock %} From 63075a6fe92269c979f2e60fd1c5a03e24286405 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 14:21:13 -0800 Subject: [PATCH 25/69] Updates models --- bookwyrm/forms.py | 2 +- .../0126_filelink_link_linkdomain.py | 93 ++++++++++--------- bookwyrm/models/__init__.py | 2 +- bookwyrm/models/link.py | 17 +++- bookwyrm/tests/models/test_link.py | 41 ++++++++ 5 files changed, 110 insertions(+), 45 deletions(-) create mode 100644 bookwyrm/tests/models/test_link.py diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 8c3785f8f..f73da6489 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -219,7 +219,7 @@ class CoverForm(CustomForm): class FileLinkForm(CustomForm): class Meta: model = models.FileLink - exclude = ["remote_id"] + fields = ["url", "filetype", "book"] class EditionForm(CustomForm): diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 1235e81dc..52be86c5b 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.10 on 2022-01-09 21:16 +# Generated by Django 3.2.10 on 2022-01-09 22:10 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -13,6 +13,47 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name="LinkDomain", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_date", models.DateTimeField(auto_now_add=True)), + ("updated_date", models.DateTimeField(auto_now=True)), + ( + "remote_id", + bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + ("domain", models.CharField(max_length=255, unique=True)), + ( + "status", + models.CharField( + choices=[ + ("approved", "Approved"), + ("blocked", "Blocked"), + ("pending", "Pending"), + ], + default="pending", + max_length=50, + ), + ), + ("name", models.CharField(max_length=100)), + ], + options={ + "abstract": False, + }, + ), migrations.CreateModel( name="Link", fields=[ @@ -36,53 +77,21 @@ class Migration(migrations.Migration): ), ), ("url", bookwyrm.models.fields.URLField(max_length=255)), + ( + "domain", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="bookwyrm.linkdomain", + ), + ), ], options={ "abstract": False, }, bases=(bookwyrm.models.activitypub_mixin.ActivitypubMixin, models.Model), ), - migrations.CreateModel( - name="LinkDomain", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created_date", models.DateTimeField(auto_now_add=True)), - ("updated_date", models.DateTimeField(auto_now=True)), - ( - "remote_id", - bookwyrm.models.fields.RemoteIdField( - max_length=255, - null=True, - validators=[bookwyrm.models.fields.validate_remote_id], - ), - ), - ("domain", models.CharField(max_length=255)), - ( - "status", - models.CharField( - choices=[ - ("approved", "Approved"), - ("blocked", "Blocked"), - ("pending", "Pending"), - ], - default="pending", - max_length=50, - ), - ), - ("name", models.CharField(max_length=100)), - ], - options={ - "abstract": False, - }, - ), migrations.CreateModel( name="FileLink", fields=[ diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 8063d5aa9..4c6305f99 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -4,7 +4,7 @@ import sys from .book import Book, Work, Edition, BookDataModel from .author import Author -from .link import Link, FileLink +from .link import Link, FileLink, LinkDomain from .connector import Connector from .shelf import Shelf, ShelfBook diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 12a5fae19..e3c72b3f6 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -1,4 +1,6 @@ """ outlink data """ +from urllib.parse import urlparse + from django.db import models from django.utils.translation import gettext_lazy as _ @@ -12,12 +14,25 @@ class Link(ActivitypubMixin, BookWyrmModel): """a link to a website""" url = fields.URLField(max_length=255, activitypub_field="href") + domain = models.ForeignKey( + "LinkDomain", on_delete=models.PROTECT, null=True, blank=True + ) activity_serializer = activitypub.Link reverse_unfurl = True + @property + def name(self): + """link name via the assocaited domain""" + return self.domain.name + def save(self, *args, **kwargs): """create a link""" + # get or create the associated domain + if not self.domain: + domain = urlparse(self.url).netloc + self.domain, _ = LinkDomain.objects.get_or_create(domain=domain) + # this is never broadcast, the owning model broadcasts an update if "broadcast" in kwargs: del kwargs["broadcast"] @@ -43,7 +58,7 @@ StatusChoices = [ class LinkDomain(BookWyrmModel): """List of domains used in links""" - domain = models.CharField(max_length=255) + domain = models.CharField(max_length=255, unique=True) status = models.CharField(max_length=50, choices=StatusChoices, default="pending") name = models.CharField(max_length=100) diff --git a/bookwyrm/tests/models/test_link.py b/bookwyrm/tests/models/test_link.py new file mode 100644 index 000000000..8afecd6ce --- /dev/null +++ b/bookwyrm/tests/models/test_link.py @@ -0,0 +1,41 @@ +""" testing models """ +from unittest.mock import patch +from django.test import TestCase + +from bookwyrm import models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +class Link(TestCase): + """some activitypub oddness ahead""" + + def setUp(self): + """look, a list""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" + ) + work = models.Work.objects.create(title="hello") + self.book = models.Edition.objects.create(title="hi", parent_work=work) + + def test_create_domain(self, _): + """generated default name""" + domain = models.LinkDomain.objects.create(domain="beep.com") + self.assertEqual(domain.name, "beep.com") + self.assertEqual(domain.status, "pending") + + def test_create_link_new_domain(self, _): + """generates link and sets domain""" + link = models.Link.objects.create(url="https://www.hello.com/hi-there") + self.assertEqual(link.domain.domain, "www.hello.com") + self.assertEqual(link.name, "www.hello.com") + + def test_create_link_existing_domain(self, _): + """generate link with a known domain""" + domain = models.LinkDomain.objects.create(domain="www.hello.com", name="Hi") + + link = models.Link.objects.create(url="https://www.hello.com/hi-there") + self.assertEqual(link.domain, domain) + self.assertEqual(link.name, "Hi") From 70fe7e17afac1db7fb74144c6425b578deb406bd Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 14:25:22 -0800 Subject: [PATCH 26/69] Removes name ap field --- bookwyrm/activitypub/base_activity.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index f1b3ad181..90f7b0a53 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -297,7 +297,6 @@ class Link(ActivityObject): """for tagging a book in a status""" href: str - name: str mediaType: str = None id: str = None type: str = "Link" From aa9864a21ecb9b5f98f6baf47dd3e96134d1ce22 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 20:30:23 -0800 Subject: [PATCH 27/69] Only show approved links --- .../0126_filelink_link_linkdomain.py | 2 +- bookwyrm/models/link.py | 2 +- bookwyrm/templates/book/book.html | 32 +---------------- bookwyrm/templates/book/links.html | 34 +++++++++++++++++++ bookwyrm/templatetags/bookwyrm_tags.py | 6 ++++ bookwyrm/tests/views/books/test_links.py | 3 +- 6 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 bookwyrm/templates/book/links.html diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 52be86c5b..bd261102e 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -82,7 +82,7 @@ class Migration(migrations.Migration): models.ForeignKey( blank=True, null=True, - on_delete=django.db.models.deletion.PROTECT, + on_delete=django.db.models.deletion.CASCADE, to="bookwyrm.linkdomain", ), ), diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index e3c72b3f6..f2b4108b6 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -15,7 +15,7 @@ class Link(ActivitypubMixin, BookWyrmModel): url = fields.URLField(max_length=255, activitypub_field="href") domain = models.ForeignKey( - "LinkDomain", on_delete=models.PROTECT, null=True, blank=True + "LinkDomain", on_delete=models.CASCADE, null=True, blank=True ) activity_serializer = activitypub.Link diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 6467bb71a..1060f0381 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -383,37 +383,7 @@ {% endif %}
-
-
-

{% trans "Get a copy" %}

-
- {% if can_edit_book %} -
- {% url 'file-link' book.id as fallback_url %} - -
- {% endif %} -
- {% if book.file_links %} -
    - {% for link in book.file_links.all %} -
  • - {{ link.name }} - ({{ link.filetype }}) -
  • - {% endfor %} -
- {% endif %} - - {% if can_edit_book %} - {% include 'book/file_link_modal.html' with book=book id="edit-links" %} - {% endif %} + {% include "book/links.html" %}
diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/links.html new file mode 100644 index 000000000..6bce3c9ba --- /dev/null +++ b/bookwyrm/templates/book/links.html @@ -0,0 +1,34 @@ +{% load i18n %} +{% load bookwyrm_tags %} +{% get_book_file_links book as links %} +
+
+

{% trans "Get a copy" %}

+
+ {% if can_edit_book %} +
+ {% url 'file-link' book.id as fallback_url %} + +
+ {% endif %} +
+{% if links %} +
    + {% for link in links.all %} +
  • + {{ link.name }} + ({{ link.filetype }}) +
  • + {% endfor %} +
+{% endif %} + +{% if can_edit_book %} +{% include 'book/file_link_modal.html' with book=book id="edit-links" %} +{% endif %} diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py index f24219d25..c6781f5af 100644 --- a/bookwyrm/templatetags/bookwyrm_tags.py +++ b/bookwyrm/templatetags/bookwyrm_tags.py @@ -177,3 +177,9 @@ def suggested_books(context): # this happens here instead of in the view so that the template snippet can # be cached in the template return get_suggested_books(context["request"].user) + + +@register.simple_tag(takes_context=False) +def get_book_file_links(book): + """links for a book""" + return book.file_links.filter(domain__status="approved") diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index 136a76066..1214e0e2e 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -63,7 +63,6 @@ class LinkViews(TestCase): """there are so many views, this just makes sure it LOADS""" view = views.FileLink.as_view() form = forms.FileLinkForm() - form.data["name"] = "hi" form.data["url"] = "https://www.example.com" form.data["filetype"] = "HTML" form.data["book"] = self.book.id @@ -81,7 +80,7 @@ class LinkViews(TestCase): self.assertEqual(activity["object"]["type"], "Edition") link = models.FileLink.objects.get() - self.assertEqual(link.name, "hi") + self.assertEqual(link.name, "www.example.com") self.assertEqual(link.url, "https://www.example.com") self.assertEqual(link.filetype, "HTML") From 0bfa15bb47cc6f87fc27217b04460225e6cfe1a7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 20:48:16 -0800 Subject: [PATCH 28/69] Adds id on static link edit view --- bookwyrm/templates/book/file_link_page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/book/file_link_page.html b/bookwyrm/templates/book/file_link_page.html index ba1e61d0f..26a8d89d3 100644 --- a/bookwyrm/templates/book/file_link_page.html +++ b/bookwyrm/templates/book/file_link_page.html @@ -6,5 +6,5 @@ {% endblock %} {% block content %} -{% include "book/file_link_modal.html" with book=book active=True static=True %} +{% include "book/file_link_modal.html" with book=book active=True static=True id="file-link" %} {% endblock %} From 32e3fdb438a2cfd66aa596b47ae43575c04dc214 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 10:11:00 -0800 Subject: [PATCH 29/69] Adds admin view --- bookwyrm/activitypub/base_activity.py | 1 + .../0126_filelink_link_linkdomain.py | 1 + bookwyrm/models/link.py | 2 +- bookwyrm/templates/settings/layout.html | 4 + .../settings/link_domains/link_domains.html | 95 +++++++++++++++++++ bookwyrm/urls.py | 10 +- bookwyrm/views/__init__.py | 1 + bookwyrm/views/admin/link_domains.py | 32 +++++++ 8 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 bookwyrm/templates/settings/link_domains/link_domains.html create mode 100644 bookwyrm/views/admin/link_domains.py diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 90f7b0a53..f1b3ad181 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -297,6 +297,7 @@ class Link(ActivityObject): """for tagging a book in a status""" href: str + name: str mediaType: str = None id: str = None type: str = "Link" diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index bd261102e..98d71cc26 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -83,6 +83,7 @@ class Migration(migrations.Migration): blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, + related_name="links", to="bookwyrm.linkdomain", ), ), diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index f2b4108b6..41760cc21 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -15,7 +15,7 @@ class Link(ActivitypubMixin, BookWyrmModel): url = fields.URLField(max_length=255, activitypub_field="href") domain = models.ForeignKey( - "LinkDomain", on_delete=models.CASCADE, null=True, blank=True + "LinkDomain", on_delete=models.CASCADE, null=True, blank=True, related_name="links" ) activity_serializer = activitypub.Link diff --git a/bookwyrm/templates/settings/layout.html b/bookwyrm/templates/settings/layout.html index d7a840af5..200164ba3 100644 --- a/bookwyrm/templates/settings/layout.html +++ b/bookwyrm/templates/settings/layout.html @@ -62,6 +62,10 @@ {% url 'settings-ip-blocks' as url %} {% trans "IP Address Blocklist" %} +
  • + {% url 'settings-link-domain' status='pending' as url %} + {% trans "Link Domains" %} +
  • {% endif %} {% if perms.bookwyrm.edit_instance_settings %} diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html new file mode 100644 index 000000000..555a81a11 --- /dev/null +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -0,0 +1,95 @@ +{% extends 'settings/layout.html' %} +{% load humanize %} +{% load i18n %} + +{% block title %}{% trans "Link Domains" %}{% endblock %} + +{% block header %}{% trans "Link Domains" %}{% endblock %} + +{% block panel %} +

    + {% trans "Link domains must be approved before they are shown on book pages. Please make sure that the domains are not hosting spam, malicious code, or deceptive links before approving." %} +

    + +
    +
    + +
    + + {% for domain in domains %} +
    +
    +
    +

    + {{ domain.name }} + ({{ domain.domain }}) +

    +
    +
    + {% trans "Set name" as button_text %} + {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit_domain" controls_uid=domain.id focus="id_description" %} +
    +
    +
    +
    + + + {% trans "View links" %} + ({{ domain.links.count }}) + + + + +
      + {% for link in domain.links.all|slice:10 %} +
    • + {{ link.url }} + {% if link.filelink.filetype %} + ({{ link.filelink.filetype }}) + {% endif %} +
    • + {% endfor %} +
    +
    +
    + +
    + {% csrf_token %} +
    +
    + +
    +
    + +
    +
    +
    +
    + {% endfor %} + + {% if not domains.exists %} + {% if status == "approved" %} + {% trans "No domains currently approved" %} + {% elif status == "pending" %} + {% trans "No domains currently pending" %} + {% else %} + {% trans "No domains currently blocked" %} + {% endif %} + {% endif %} +
    + +{% endblock %} + diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 397a8a414..61ff7ffaa 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -96,11 +96,6 @@ urlpatterns = [ re_path( r"^settings/users/?$", views.UserAdminList.as_view(), name="settings-users" ), - re_path( - r"^settings/users/(?P\d+)/?$", - views.UserAdmin.as_view(), - name="settings-user", - ), re_path( r"^settings/federation/(?P(federated|blocked))?/?$", views.Federation.as_view(), @@ -158,6 +153,11 @@ urlpatterns = [ views.EmailBlocklist.as_view(), name="settings-email-blocks-delete", ), + re_path( + r"^setting/link-domains/(?P(pending|approved|blocked))/?", + views.LinkDomain.as_view(), + name="settings-link-domain", + ), re_path( r"^settings/ip-blocklist/?$", views.IPBlocklist.as_view(), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index bc8ac2a3d..d3d807039 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -9,6 +9,7 @@ from .admin.email_blocklist import EmailBlocklist from .admin.ip_blocklist import IPBlocklist from .admin.invite import ManageInvites, Invite, InviteRequest from .admin.invite import ManageInviteRequests, ignore_invite_request +from .admin.link_domains import LinkDomain from .admin.reports import ( Report, Reports, diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py new file mode 100644 index 000000000..0b662b850 --- /dev/null +++ b/bookwyrm/views/admin/link_domains.py @@ -0,0 +1,32 @@ +""" Manage link domains""" +from django.contrib.auth.decorators import login_required, permission_required +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View + +from bookwyrm import forms, models + +# pylint: disable=no-self-use +@method_decorator(login_required, name="dispatch") +@method_decorator( + permission_required("bookwyrm.moderate_user", raise_exception=True), + name="dispatch", +) +class LinkDomain(View): + """Moderate links""" + + def get(self, request, status="pending"): + """view pending domains""" + data = { + "domains": models.LinkDomain.objects.filter( + status=status + ).prefetch_related("links"), + "form": forms.EmailBlocklistForm(), + "status": status, + } + return TemplateResponse( + request, "settings/link_domains/link_domains.html", data + ) + + def post(self, request): + """post?""" From f580a51f24dac593caa967430b430c89ad482342 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 10:38:05 -0800 Subject: [PATCH 30/69] Form to edit link domain display names --- bookwyrm/forms.py | 6 +++++ .../link_domains/edit_domain_modal.html | 25 +++++++++++++++++++ .../settings/link_domains/link_domains.html | 10 ++++++-- bookwyrm/urls.py | 7 +++++- 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 bookwyrm/templates/settings/link_domains/edit_domain_modal.html diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index f73da6489..12ebbff85 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -216,6 +216,12 @@ class CoverForm(CustomForm): help_texts = {f: None for f in fields} +class LinkDomainForm(CustomForm): + class Meta: + model = models.LinkDomain + fields = ["id", "name"] + + class FileLinkForm(CustomForm): class Meta: model = models.FileLink diff --git a/bookwyrm/templates/settings/link_domains/edit_domain_modal.html b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html new file mode 100644 index 000000000..7b2a46e24 --- /dev/null +++ b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html @@ -0,0 +1,25 @@ +{% extends 'components/modal.html' %} +{% load i18n %} + +{% block modal-title %} +{% blocktrans with url=domain.domain %}Set display name for {{ url }}{% endblocktrans %} +{% endblock %} + +{% block modal-form-open %} +
    +{% endblock %} + +{% block modal-body %} +{% csrf_token %} + +
    + +
    +{% endblock %} + +{% block modal-footer %} + + +{% endblock %} + +{% block modal-form-close %}
    {% endblock %} diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index 555a81a11..3d89929dc 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -1,6 +1,7 @@ {% extends 'settings/layout.html' %} {% load humanize %} {% load i18n %} +{% load utilities %} {% block title %}{% trans "Link Domains" %}{% endblock %} @@ -30,6 +31,7 @@
    {% for domain in domains %} + {% join "domain" domain.id as domain_modal %}
    @@ -39,8 +41,10 @@
    - {% trans "Set name" as button_text %} - {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit_domain" controls_uid=domain.id focus="id_description" %} +
    @@ -66,6 +70,8 @@
    + {% include "settings/link_domains/edit_domain_modal.html" with domain=domain id=domain_modal %} +
    {% csrf_token %}
    diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 61ff7ffaa..781430dc1 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -154,7 +154,12 @@ urlpatterns = [ name="settings-email-blocks-delete", ), re_path( - r"^setting/link-domains/(?P(pending|approved|blocked))/?", + r"^setting/link-domains/(?P(pending|approved|blocked|))/?", + views.LinkDomain.as_view(), + name="settings-link-domain", + ), + re_path( + r"^setting/link-domains/?", views.LinkDomain.as_view(), name="settings-link-domain", ), From 3f280af715d800f8d8cb7ab610696abb226e8f41 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 10:48:27 -0800 Subject: [PATCH 31/69] Functionality to edit name --- bookwyrm/forms.py | 2 +- .../settings/link_domains/edit_domain_modal.html | 4 ++-- bookwyrm/urls.py | 4 ++-- bookwyrm/views/admin/link_domains.py | 11 ++++++++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 12ebbff85..5ad365011 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -219,7 +219,7 @@ class CoverForm(CustomForm): class LinkDomainForm(CustomForm): class Meta: model = models.LinkDomain - fields = ["id", "name"] + fields = ["name"] class FileLinkForm(CustomForm): diff --git a/bookwyrm/templates/settings/link_domains/edit_domain_modal.html b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html index 7b2a46e24..984ad78d3 100644 --- a/bookwyrm/templates/settings/link_domains/edit_domain_modal.html +++ b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html @@ -6,14 +6,14 @@ {% endblock %} {% block modal-form-open %} - + {% endblock %} {% block modal-body %} {% csrf_token %}
    - +
    {% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 781430dc1..0d41e4f5e 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -154,12 +154,12 @@ urlpatterns = [ name="settings-email-blocks-delete", ), re_path( - r"^setting/link-domains/(?P(pending|approved|blocked|))/?", + r"^setting/link-domains/(?P(pending|approved|blocked))/?$", views.LinkDomain.as_view(), name="settings-link-domain", ), re_path( - r"^setting/link-domains/?", + r"^setting/link-domains/(?P(pending|approved|blocked))/(?P\d+)/?$", views.LinkDomain.as_view(), name="settings-link-domain", ), diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py index 0b662b850..4f11af117 100644 --- a/bookwyrm/views/admin/link_domains.py +++ b/bookwyrm/views/admin/link_domains.py @@ -1,5 +1,6 @@ """ Manage link domains""" from django.contrib.auth.decorators import login_required, permission_required +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 @@ -15,7 +16,7 @@ from bookwyrm import forms, models class LinkDomain(View): """Moderate links""" - def get(self, request, status="pending"): + def get(self, request, status): """view pending domains""" data = { "domains": models.LinkDomain.objects.filter( @@ -28,5 +29,9 @@ class LinkDomain(View): request, "settings/link_domains/link_domains.html", data ) - def post(self, request): - """post?""" + def post(self, request, status, domain_id): + """Set display name""" + domain = get_object_or_404(models.LinkDomain, id=domain_id) + form = forms.LinkDomainForm(request.POST, instance=domain) + form.save() + return redirect('settings-link-domain', status=status) From 6b0967df39cc6ea7ca4d98448f7cb2057a0c952a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 11:03:10 -0800 Subject: [PATCH 32/69] Show related books in links preview --- bookwyrm/settings.py | 2 +- .../settings/link_domains/link_domains.html | 43 +++++++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 77b1b30ad..24db4b18d 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ env = Env() env.read_env() DOMAIN = env("DOMAIN") -VERSION = "0.1.2" +VERSION = "0.2.0" PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index 3d89929dc..4b300a355 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -35,10 +35,10 @@
    -

    +

    {{ domain.name }} ({{ domain.domain }}) -

    +
    -
    -
    - -
    -
    - +
    + {% if status != "approved" %} +
    + {% csrf_token %} + +
    + {% endif %} + {% if status != "blocked" %} +
    + {% csrf_token %} + +
    + {% endif %} +
    {% endfor %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 0d41e4f5e..0df259b3e 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -163,6 +163,11 @@ urlpatterns = [ views.LinkDomain.as_view(), name="settings-link-domain", ), + re_path( + r"^setting/link-domains/(?P\d+)/(?P(pending|approved|blocked))/?$", + views.update_domain_status, + name="settings-link-domain-status", + ), re_path( r"^settings/ip-blocklist/?$", views.IPBlocklist.as_view(), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index d3d807039..87cbfc69e 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -9,7 +9,7 @@ from .admin.email_blocklist import EmailBlocklist from .admin.ip_blocklist import IPBlocklist from .admin.invite import ManageInvites, Invite, InviteRequest from .admin.invite import ManageInviteRequests, ignore_invite_request -from .admin.link_domains import LinkDomain +from .admin.link_domains import LinkDomain, update_domain_status from .admin.reports import ( Report, Reports, diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py index 4f11af117..eca4421a9 100644 --- a/bookwyrm/views/admin/link_domains.py +++ b/bookwyrm/views/admin/link_domains.py @@ -4,6 +4,7 @@ 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 @@ -35,3 +36,15 @@ class LinkDomain(View): form = forms.LinkDomainForm(request.POST, instance=domain) form.save() return redirect('settings-link-domain', status=status) + + +@require_POST +@login_required +def update_domain_status(request, domain_id, status): + """This domain seems fine""" + domain = get_object_or_404(models.LinkDomain, id=domain_id) + domain.raise_not_editable(request.user) + + domain.status = status + domain.save() + return redirect('settings-link-domain', status="pending") From 4820a2f982f32584297a167e5f0fb5a31cd9719a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 11:21:03 -0800 Subject: [PATCH 34/69] Python formatting --- bookwyrm/models/link.py | 6 +++++- bookwyrm/views/admin/link_domains.py | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 7b7273df5..6e02c8d39 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -16,7 +16,11 @@ class Link(ActivitypubMixin, BookWyrmModel): url = fields.URLField(max_length=255, activitypub_field="href") domain = models.ForeignKey( - "LinkDomain", on_delete=models.CASCADE, null=True, blank=True, related_name="links" + "LinkDomain", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="links", ) activity_serializer = activitypub.Link diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py index eca4421a9..0d7bfd251 100644 --- a/bookwyrm/views/admin/link_domains.py +++ b/bookwyrm/views/admin/link_domains.py @@ -20,9 +20,9 @@ class LinkDomain(View): def get(self, request, status): """view pending domains""" data = { - "domains": models.LinkDomain.objects.filter( - status=status - ).prefetch_related("links"), + "domains": models.LinkDomain.objects.filter(status=status).prefetch_related( + "links" + ), "form": forms.EmailBlocklistForm(), "status": status, } @@ -35,7 +35,7 @@ class LinkDomain(View): domain = get_object_or_404(models.LinkDomain, id=domain_id) form = forms.LinkDomainForm(request.POST, instance=domain) form.save() - return redirect('settings-link-domain', status=status) + return redirect("settings-link-domain", status=status) @require_POST @@ -47,4 +47,4 @@ def update_domain_status(request, domain_id, status): domain.status = status domain.save() - return redirect('settings-link-domain', status="pending") + return redirect("settings-link-domain", status="pending") From 4dfe9fd714d38a9d6fddd282558b3730a379618b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 11:21:43 -0800 Subject: [PATCH 35/69] Support links with no name --- bookwyrm/activitypub/base_activity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index f1b3ad181..fcc4eccde 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -297,7 +297,7 @@ class Link(ActivityObject): """for tagging a book in a status""" href: str - name: str + name: str = None mediaType: str = None id: str = None type: str = "Link" From 8ba3a4ab00d40dcda805396f291e0ccfd14ce8df Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 11:47:52 -0800 Subject: [PATCH 36/69] Adds link confirmation modal --- bookwyrm/settings.py | 2 +- bookwyrm/static/js/bookwyrm.js | 2 +- .../book/link_verification_modal.html | 22 +++++++++++++++++++ bookwyrm/templates/book/links.html | 9 +++++++- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 bookwyrm/templates/book/link_verification_modal.html diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 24db4b18d..122cae1b8 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -14,7 +14,7 @@ VERSION = "0.2.0" PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") -JS_CACHE = "2d3181e1" +JS_CACHE = "a47cc2ca" # email EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend") diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index cf3944b35..94163787d 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -35,7 +35,7 @@ let BookWyrm = new (class { .forEach((node) => node.addEventListener("change", this.disableIfTooLarge.bind(this))); document - .querySelectorAll("button[data-modal-open]") + .querySelectorAll("[data-modal-open]") .forEach((node) => node.addEventListener("click", this.handleModalButton.bind(this))); document diff --git a/bookwyrm/templates/book/link_verification_modal.html b/bookwyrm/templates/book/link_verification_modal.html new file mode 100644 index 000000000..ed7dca8e6 --- /dev/null +++ b/bookwyrm/templates/book/link_verification_modal.html @@ -0,0 +1,22 @@ +{% extends 'components/modal.html' %} +{% load i18n %} + +{% block modal-title %} +{% trans "Leaving BookWyrm" %} +{% endblock %} + + +{% block modal-body %} + +{% blocktrans trimmed with link_url=link.url %} +This link is taking you to {{ link_url }}. Is that where you'd like to go? +{% endblocktrans %} + +{% endblock %} + + +{% block modal-footer %} +{% trans "Continue" %} + + +{% endblock %} diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/links.html index 6bce3c9ba..83d4f0534 100644 --- a/bookwyrm/templates/book/links.html +++ b/bookwyrm/templates/book/links.html @@ -1,5 +1,7 @@ {% load i18n %} {% load bookwyrm_tags %} +{% load utilities %} + {% get_book_file_links book as links %}
    @@ -21,12 +23,17 @@ {% if links %} +{% for link in links.all %} +{% join "verify" link.id as verify_modal %} +{% include "book/link_verification_modal.html" with id=verify_modal %} +{% endfor %} {% endif %} {% if can_edit_book %} From d610115a5b894cdc8d31b8885489ef5dc40726e8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 11:52:00 -0800 Subject: [PATCH 37/69] Null state for links --- bookwyrm/management/commands/initdb.py | 38 +++++++++++++++---- .../0126_filelink_link_linkdomain.py | 3 ++ bookwyrm/templates/book/links.html | 5 +++ .../settings/link_domains/link_domains.html | 6 +-- bookwyrm/views/admin/link_domains.py | 5 +++ 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index d0ab648e0..53d6e8d49 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -3,7 +3,7 @@ from django.core.management.base import BaseCommand from django.contrib.auth.models import Group, Permission from django.contrib.contenttypes.models import ContentType -from bookwyrm.models import Connector, FederatedServer, SiteSettings, User +from bookwyrm import models def init_groups(): @@ -55,7 +55,7 @@ def init_permissions(): }, ] - content_type = ContentType.objects.get_for_model(User) + content_type = models.ContentType.objects.get_for_model(User) for permission in permissions: permission_obj = Permission.objects.create( codename=permission["codename"], @@ -72,7 +72,7 @@ def init_permissions(): def init_connectors(): """access book data sources""" - Connector.objects.create( + models.Connector.objects.create( identifier="bookwyrm.social", name="BookWyrm dot Social", connector_file="bookwyrm_connector", @@ -84,7 +84,7 @@ def init_connectors(): priority=2, ) - Connector.objects.create( + models.Connector.objects.create( identifier="inventaire.io", name="Inventaire", connector_file="inventaire", @@ -96,7 +96,7 @@ def init_connectors(): priority=3, ) - Connector.objects.create( + models.Connector.objects.create( identifier="openlibrary.org", name="OpenLibrary", connector_file="openlibrary", @@ -113,7 +113,7 @@ def init_federated_servers(): """big no to nazis""" built_in_blocks = ["gab.ai", "gab.com"] for server in built_in_blocks: - FederatedServer.objects.create( + models.FederatedServer.objects.create( server_name=server, status="blocked", ) @@ -121,12 +121,36 @@ def init_federated_servers(): def init_settings(): """info about the instance""" - SiteSettings.objects.create( + models.SiteSettings.objects.create( support_link="https://www.patreon.com/bookwyrm", support_title="Patreon", ) +def init_link_domains(*_): + """safe book links""" + models.LinkDomain.objects.create( + domain="www.gutenberg.org", + name="Project Gutenberg", + status="approved", + ) + models.LinkDomain.objects.create( + domain="archive.org", + name="Internet Archive", + status="approved", + ) + models.LinkDomain.objects.create( + domain="openlibrary.org", + name="Open Library", + status="approved", + ) + models.LinkDomain.objects.create( + domain="theanarchistlibrary.org", + name="The Anarchist Library", + status="approved", + ) + + class Command(BaseCommand): help = "Initializes the database with starter data" diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 98d71cc26..1870030cd 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -5,6 +5,8 @@ import bookwyrm.models.fields from django.db import migrations, models import django.db.models.deletion +from bookwyrm.management.commands.initdb import init_link_domains + class Migration(migrations.Migration): @@ -123,4 +125,5 @@ class Migration(migrations.Migration): }, bases=("bookwyrm.link",), ), + migrations.RunPython(init_link_domains, reverse_code=migrations.RunPython.noop), ] diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/links.html index 83d4f0534..f87d56815 100644 --- a/bookwyrm/templates/book/links.html +++ b/bookwyrm/templates/book/links.html @@ -3,6 +3,7 @@ {% load utilities %} {% get_book_file_links book as links %} +{% if links.exists or request.user.is_authenticated %}

    {% trans "Get a copy" %}

    @@ -34,8 +35,12 @@ {% join "verify" link.id as verify_modal %} {% include "book/link_verification_modal.html" with id=verify_modal %} {% endfor %} +{% else %} +{% trans "No links available" %} {% endif %} {% if can_edit_book %} {% include 'book/file_link_modal.html' with book=book id="edit-links" %} {% endif %} + +{% endif %} diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index cb084967b..dc7fdbd49 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -17,15 +17,15 @@
    diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py index 0d7bfd251..aab6625c9 100644 --- a/bookwyrm/views/admin/link_domains.py +++ b/bookwyrm/views/admin/link_domains.py @@ -23,6 +23,11 @@ class LinkDomain(View): "domains": models.LinkDomain.objects.filter(status=status).prefetch_related( "links" ), + "counts": { + "pending": models.LinkDomain.objects.filter(status="pending").count(), + "approved": models.LinkDomain.objects.filter(status="approved").count(), + "blocked": models.LinkDomain.objects.filter(status="blocked").count(), + }, "form": forms.EmailBlocklistForm(), "status": status, } From 62f481c85949d625ea35eaeaadcf80610e1a592f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 12:21:36 -0800 Subject: [PATCH 38/69] Fixes urls --- .../templates/settings/link_domains/edit_domain_modal.html | 2 +- bookwyrm/urls.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/settings/link_domains/edit_domain_modal.html b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html index 984ad78d3..135783e78 100644 --- a/bookwyrm/templates/settings/link_domains/edit_domain_modal.html +++ b/bookwyrm/templates/settings/link_domains/edit_domain_modal.html @@ -13,7 +13,7 @@ {% csrf_token %}
    - +
    {% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 0df259b3e..c9d4cb924 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -96,6 +96,11 @@ urlpatterns = [ re_path( r"^settings/users/?$", views.UserAdminList.as_view(), name="settings-users" ), + re_path( + r"^settings/users/(?P\d+)/?$", + views.UserAdmin.as_view(), + name="settings-user", + ), re_path( r"^settings/federation/(?P(federated|blocked))?/?$", views.Federation.as_view(), From eec1155bb8128413c46b7672284aebd7d5455e3f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 12:29:28 -0800 Subject: [PATCH 39/69] Adds admin view tests --- .../tests/views/admin/test_link_domains.py | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 bookwyrm/tests/views/admin/test_link_domains.py diff --git a/bookwyrm/tests/views/admin/test_link_domains.py b/bookwyrm/tests/views/admin/test_link_domains.py new file mode 100644 index 000000000..652c82c80 --- /dev/null +++ b/bookwyrm/tests/views/admin/test_link_domains.py @@ -0,0 +1,78 @@ +""" test for app action functionality """ +from unittest.mock import patch + +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import models, views +from bookwyrm.tests.validate_html import validate_html + + +class LinkDomainViews(TestCase): + """every response to a get request, html or json""" + + def setUp(self): + """we need basic test data and mocks""" + self.factory = RequestFactory() + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.mouse", + "password", + local=True, + localname="mouse", + ) + self.book = models.Edition.objects.create(title="hello") + models.FileLink.objects.create( + book=self.book, + url="https://beep.com/book/1", + ) + + + models.SiteSettings.objects.create() + + def test_domain_page_get(self): + """there are so many views, this just makes sure it LOADS""" + view = views.LinkDomain.as_view() + request = self.factory.get("") + request.user = self.local_user + request.user.is_superuser = True + + result = view(request, "pending") + + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_domain_page_post(self): + """there are so many views, this just makes sure it LOADS""" + domain = models.LinkDomain.objects.get() + self.assertEqual(domain.name, "beep.com") + + view = views.LinkDomain.as_view() + request = self.factory.post("", {"name": "ugh"}) + request.user = self.local_user + request.user.is_superuser = True + + result = view(request, "pending", domain.id) + self.assertEqual(result.status_code, 301) + + self.assertEqual(domain.name, "ugh") + + def test_domain_page_set_status(self): + """there are so many views, this just makes sure it LOADS""" + domain = models.LinkDomain.objects.get() + self.assertEqual(domain.status, "pending") + + view = views.LinkDomain.as_view() + request = self.factory.post("") + request.user = self.local_user + request.user.is_superuser = True + + result = view(request, domain.id, "approved") + self.assertEqual(result.status_code, 301) + + self.assertEqual(domain.status, "approved") From 2880b311e1a6aa5ac226c6be798d9f159edd64de Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 12:30:24 -0800 Subject: [PATCH 40/69] HTML validity fix for summary tag --- bookwyrm/templates/settings/link_domains/link_domains.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index dc7fdbd49..7859f3db1 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -50,10 +50,10 @@
    -

    + {% trans "View links" %} ({{ domain.links.count }}) -

    +
    From 8928e8da26ed9172c105693361a6bcd30e6aac41 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 12:33:49 -0800 Subject: [PATCH 41/69] Corrects tests --- bookwyrm/tests/views/admin/test_link_domains.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bookwyrm/tests/views/admin/test_link_domains.py b/bookwyrm/tests/views/admin/test_link_domains.py index 652c82c80..8c972ea10 100644 --- a/bookwyrm/tests/views/admin/test_link_domains.py +++ b/bookwyrm/tests/views/admin/test_link_domains.py @@ -31,7 +31,6 @@ class LinkDomainViews(TestCase): url="https://beep.com/book/1", ) - models.SiteSettings.objects.create() def test_domain_page_get(self): @@ -49,7 +48,7 @@ class LinkDomainViews(TestCase): def test_domain_page_post(self): """there are so many views, this just makes sure it LOADS""" - domain = models.LinkDomain.objects.get() + domain = models.LinkDomain.objects.get(domain="beep.com") self.assertEqual(domain.name, "beep.com") view = views.LinkDomain.as_view() @@ -58,21 +57,23 @@ class LinkDomainViews(TestCase): request.user.is_superuser = True result = view(request, "pending", domain.id) - self.assertEqual(result.status_code, 301) + self.assertEqual(result.status_code, 302) + domain.refresh_from_db() self.assertEqual(domain.name, "ugh") def test_domain_page_set_status(self): """there are so many views, this just makes sure it LOADS""" - domain = models.LinkDomain.objects.get() + domain = models.LinkDomain.objects.get(domain="beep.com") self.assertEqual(domain.status, "pending") - view = views.LinkDomain.as_view() + view = views.update_domain_status request = self.factory.post("") request.user = self.local_user request.user.is_superuser = True result = view(request, domain.id, "approved") - self.assertEqual(result.status_code, 301) + self.assertEqual(result.status_code, 302) + domain.refresh_from_db() self.assertEqual(domain.status, "approved") From dcf51020bc2ae2e9f2bccc7def1c29646e6e378e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 13:05:08 -0800 Subject: [PATCH 42/69] Removes initialization from migration Just doesn't seem right --- bookwyrm/management/commands/initdb.py | 31 ++++++++++++++++--- .../commands/populate_lists_streams.py | 7 ----- .../0126_filelink_link_linkdomain.py | 3 -- bw-dev | 4 +-- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index 53d6e8d49..826a24e2e 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -154,9 +154,30 @@ def init_link_domains(*_): class Command(BaseCommand): help = "Initializes the database with starter data" + def add_arguments(self, parser): + parser.add_argument( + "--limit", + default=None, + help="Limit init to specific table", + ) + def handle(self, *args, **options): - init_groups() - init_permissions() - init_connectors() - init_federated_servers() - init_settings() + limit = options.get("limit") + tables = [ + "group", "permission", "connector", "federatedserver", "settings", "linkdomain" + ] + if limit not in tables: + raise Exception("Invalid table limit:", limit) + + if not limit or limit == "group": + init_groups() + if not limit or limit == "permission": + init_permissions() + if not limit or limit == "connector": + init_connectors() + if not limit or limit == "federatedserver": + init_federated_servers() + if not limit or limit == "settings": + init_settings() + if not limit or limit == "linkdomain": + init_link_domains() diff --git a/bookwyrm/management/commands/populate_lists_streams.py b/bookwyrm/management/commands/populate_lists_streams.py index e3c30baba..0a057401c 100644 --- a/bookwyrm/management/commands/populate_lists_streams.py +++ b/bookwyrm/management/commands/populate_lists_streams.py @@ -22,13 +22,6 @@ class Command(BaseCommand): help = "Populate list streams for all users" - def add_arguments(self, parser): - parser.add_argument( - "--stream", - default=None, - help="Specifies which time of stream to populate", - ) - # pylint: disable=no-self-use,unused-argument def handle(self, *args, **options): """run feed builder""" diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 1870030cd..98d71cc26 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -5,8 +5,6 @@ import bookwyrm.models.fields from django.db import migrations, models import django.db.models.deletion -from bookwyrm.management.commands.initdb import init_link_domains - class Migration(migrations.Migration): @@ -125,5 +123,4 @@ class Migration(migrations.Migration): }, bases=("bookwyrm.link",), ), - migrations.RunPython(init_link_domains, reverse_code=migrations.RunPython.noop), ] diff --git a/bw-dev b/bw-dev index 6bf5a125e..c72a96ca2 100755 --- a/bw-dev +++ b/bw-dev @@ -31,7 +31,7 @@ function execweb { function initdb { execweb python manage.py migrate - execweb python manage.py initdb + execweb python manage.py initdb "$@" } function makeitblack { @@ -65,7 +65,7 @@ case "$CMD" in docker-compose run --rm --service-ports web ;; initdb) - initdb + initdb "$@" ;; resetdb) clean From 93fead47ef0efa5e50d422220cf5100b4a82646b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 13:13:28 -0800 Subject: [PATCH 43/69] Reformats init command and adds Standard EBooks --- bookwyrm/management/commands/initdb.py | 40 ++++++++++++-------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index 826a24e2e..37dd66af4 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -129,26 +129,19 @@ def init_settings(): def init_link_domains(*_): """safe book links""" - models.LinkDomain.objects.create( - domain="www.gutenberg.org", - name="Project Gutenberg", - status="approved", - ) - models.LinkDomain.objects.create( - domain="archive.org", - name="Internet Archive", - status="approved", - ) - models.LinkDomain.objects.create( - domain="openlibrary.org", - name="Open Library", - status="approved", - ) - models.LinkDomain.objects.create( - domain="theanarchistlibrary.org", - name="The Anarchist Library", - status="approved", - ) + domains = [ + ("standardebooks.org", "Standard EBooks"), + ("www.gutenberg.org", "Project Gutenberg"), + ("archive.org", "Internet Archive"), + ("openlibrary.org", "Open Library"), + ("theanarchistlibrary.org", "The Anarchist Library"), + ] + for domain, name in domains: + models.LinkDomain.objects.create( + domain=domain, + name=name, + status="approved", + ) class Command(BaseCommand): @@ -164,7 +157,12 @@ class Command(BaseCommand): def handle(self, *args, **options): limit = options.get("limit") tables = [ - "group", "permission", "connector", "federatedserver", "settings", "linkdomain" + "group", + "permission", + "connector", + "federatedserver", + "settings", + "linkdomain", ] if limit not in tables: raise Exception("Invalid table limit:", limit) From 6c78a7b6ef5502b3233f467fda98222183d0e427 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 13:20:14 -0800 Subject: [PATCH 44/69] Add user attribution to links and domains --- bookwyrm/activitypub/base_activity.py | 1 + .../0126_filelink_link_linkdomain.py | 20 ++++++++++++++++++- bookwyrm/models/link.py | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index fcc4eccde..57244484a 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -300,6 +300,7 @@ class Link(ActivityObject): name: str = None mediaType: str = None id: str = None + attributedTo: str = None type: str = "Link" def serialize(self, **kwargs): diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 98d71cc26..7e5186b6d 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -1,7 +1,8 @@ -# Generated by Django 3.2.10 on 2022-01-09 22:10 +# Generated by Django 3.2.10 on 2022-01-10 21:20 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields +from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -49,6 +50,15 @@ class Migration(migrations.Migration): ), ), ("name", models.CharField(max_length=100)), + ( + "reported_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ "abstract": False, @@ -77,6 +87,14 @@ class Migration(migrations.Migration): ), ), ("url", bookwyrm.models.fields.URLField(max_length=255)), + ( + "added_by", + bookwyrm.models.fields.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), ( "domain", models.ForeignKey( diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 6e02c8d39..22241dddf 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -22,6 +22,9 @@ class Link(ActivitypubMixin, BookWyrmModel): blank=True, related_name="links", ) + added_by = fields.ForeignKey( + "User", on_delete=models.SET_NULL, null=True, activitypub_field="attributedTo" + ) activity_serializer = activitypub.Link reverse_unfurl = True @@ -66,6 +69,9 @@ class LinkDomain(BookWyrmModel): domain = models.CharField(max_length=255, unique=True) status = models.CharField(max_length=50, choices=StatusChoices, default="pending") name = models.CharField(max_length=100) + reported_by = models.ForeignKey( + "User", blank=True, null=True, on_delete=models.SET_NULL + ) def raise_not_editable(self, viewer): if viewer.has_perm("moderate_post"): From 34f375c53cd63795ace4821bd7a0bae3a780cffc Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 13:27:01 -0800 Subject: [PATCH 45/69] Store user that added link --- bookwyrm/forms.py | 2 +- bookwyrm/models/link.py | 9 ++++++--- bookwyrm/templates/book/file_link_modal.html | 1 + bookwyrm/tests/views/books/test_links.py | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 5ad365011..e08f3a3a5 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -225,7 +225,7 @@ class LinkDomainForm(CustomForm): class FileLinkForm(CustomForm): class Meta: model = models.FileLink - fields = ["url", "filetype", "book"] + fields = ["url", "filetype", "book", "added_by"] class EditionForm(CustomForm): diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 22241dddf..3e21642f2 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -15,6 +15,12 @@ class Link(ActivitypubMixin, BookWyrmModel): """a link to a website""" url = fields.URLField(max_length=255, activitypub_field="href") + added_by = fields.ForeignKey( + "User", + on_delete=models.SET_NULL, + null=True, + activitypub_field="attributedTo" + ) domain = models.ForeignKey( "LinkDomain", on_delete=models.CASCADE, @@ -22,9 +28,6 @@ class Link(ActivitypubMixin, BookWyrmModel): blank=True, related_name="links", ) - added_by = fields.ForeignKey( - "User", on_delete=models.SET_NULL, null=True, activitypub_field="attributedTo" - ) activity_serializer = activitypub.Link reverse_unfurl = True diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 04e215574..379f1a077 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -12,6 +12,7 @@ {% block modal-body %} {% csrf_token %} +

    {% trans "Links from unknown domains will need to be approved by a moderator before they are added." %} diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index 1214e0e2e..1961bde00 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -66,6 +66,7 @@ class LinkViews(TestCase): form.data["url"] = "https://www.example.com" form.data["filetype"] = "HTML" form.data["book"] = self.book.id + form.data["added_by"] = self.local_user request = self.factory.post("", form.data) request.user = self.local_user From 651d468b13c3157020e2217f1b89bfbc044b5243 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 13:33:22 -0800 Subject: [PATCH 46/69] Show who added the link in admin view --- bookwyrm/templates/settings/link_domains/link_domains.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index 7859f3db1..83190029c 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -61,6 +61,7 @@ + @@ -69,6 +70,9 @@ + + +{% endblock %} + +{% block additional_data %} + + +{% endblock %} diff --git a/bookwyrm/templates/settings/reports/report_preview.html b/bookwyrm/templates/settings/reports/report_preview.html index 363783d50..31bde0a1e 100644 --- a/bookwyrm/templates/settings/reports/report_preview.html +++ b/bookwyrm/templates/settings/reports/report_preview.html @@ -1,9 +1,13 @@ {% extends 'components/card.html' %} {% load i18n %} {% load humanize %} +{% load utilities %} + {% block card-header %}

    - {% blocktrans with report_id=report.id username=report.user.username %}Report #{{ report_id }}: {{ username }}{% endblocktrans %} + + {% include "settings/reports/report_header.html" with report=report %} +

    {% endblock %} @@ -17,7 +21,7 @@ {% block card-footer %} {% else %} -

    {% trans "Actions" %}

    +

    {% trans "User Actions" %}

    -
    - {% if user.is_active %} -

    - {% trans "Send direct message" %} -

    - {% endif %} +
    +
    + {% if user.is_active %} +

    + {% trans "Send direct message" %} +

    + {% endif %} - {% if user.is_active or user.deactivation_reason == "pending" %} -
    - {% csrf_token %} - - - {% else %} -
    - {% csrf_token %} - - + {% if user.is_active or user.deactivation_reason == "pending" %} +
    + {% csrf_token %} + + + {% else %} +
    + {% csrf_token %} + + + {% endif %} + + {% if user.local %} +
    + {% trans "Permanently delete user" as button_text %} + {% include "snippets/toggle/open_button.html" with controls_text="delete_user" text=button_text class="is-danger is-light" %} +
    + {% endif %} +
    + + {% if user.local %} +
    + {% include "settings/users/delete_user_form.html" with controls_text="delete_user" class="mt-2 mb-2" %} +
    {% endif %} {% if user.local %}
    - {% trans "Permanently delete user" as button_text %} - {% include "snippets/toggle/open_button.html" with controls_text="delete_user" text=button_text class="is-danger is-light" %} +
    + {% csrf_token %} + + {% if group_form.non_field_errors %} + {{ group_form.non_field_errors }} + {% endif %} + {% with group=user.groups.first %} +
    + +
    + + {% include 'snippets/form_errors.html' with errors_list=group_form.groups.errors id="desc_user_group" %} + {% endwith %} + +
    - {% endif %} -
    - - {% if user.local %} -
    - {% include "settings/users/delete_user_form.html" with controls_text="delete_user" class="mt-2 mb-2" %} -
    - {% endif %} - - {% if user.local %} -
    -
    - {% csrf_token %} - - {% if group_form.non_field_errors %} - {{ group_form.non_field_errors }} - {% endif %} - {% with group=user.groups.first %} -
    - -
    - - {% include 'snippets/form_errors.html' with errors_list=group_form.groups.errors id="desc_user_group" %} - {% endwith %} - -
    {% endif %} diff --git a/bookwyrm/templates/snippets/report_button.html b/bookwyrm/templates/snippets/report_button.html index 6b4a3f253..9d94d2af1 100644 --- a/bookwyrm/templates/snippets/report_button.html +++ b/bookwyrm/templates/snippets/report_button.html @@ -12,6 +12,6 @@ > {% trans "Report" %} -{% include 'snippets/report_modal.html' with user=user reporter=request.user id=modal_id %} +{% include 'snippets/report_modal.html' with user=user id=modal_id status=status.id %} {% endwith %} diff --git a/bookwyrm/templates/snippets/report_modal.html b/bookwyrm/templates/snippets/report_modal.html index afd396448..7d2e52b64 100644 --- a/bookwyrm/templates/snippets/report_modal.html +++ b/bookwyrm/templates/snippets/report_modal.html @@ -1,9 +1,16 @@ {% extends 'components/modal.html' %} {% load i18n %} +{% load utilities %} {% load humanize %} {% block modal-title %} -{% blocktrans with username=user.username %}Report @{{ username }}{% endblocktrans %} +{% if status %} +{% blocktrans with username=user|username %}Report @{{ username }}'s status{% endblocktrans %} +{% elif link %} +{% blocktrans with domain=link.domain.domain %}Report {{ domain }} link{% endblocktrans %} +{% else %} +{% blocktrans with username=user|username %}Report @{{ username }}{% endblocktrans %} +{% endif %} {% endblock %} {% block modal-form-open %} @@ -13,14 +20,22 @@ {% block modal-body %} {% csrf_token %} - + {% if status %} - + +{% endif %} +{% if link %} + {% endif %}
    -

    {% blocktrans with site_name=site.name %}This report will be sent to {{ site_name }}'s moderators for review.{% endblocktrans %}

    +

    + {% blocktrans with site_name=site.name %}This report will be sent to {{ site_name }}'s moderators for review.{% endblocktrans %} + {% if link %} + {% trans "Links from this domain will be removed until your report has been reviewed." %} + {% endif %} +

    + {% endif %}
    - {% endif %} {% endif %} From dcf8a8dab91b7993c49713d436c90a950ac6194b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 15:27:33 -0800 Subject: [PATCH 50/69] Fixes settings tab highlighting --- bookwyrm/templates/settings/layout.html | 2 +- bookwyrm/urls.py | 5 +++++ bookwyrm/views/admin/link_domains.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/settings/layout.html b/bookwyrm/templates/settings/layout.html index 200164ba3..1addc8db7 100644 --- a/bookwyrm/templates/settings/layout.html +++ b/bookwyrm/templates/settings/layout.html @@ -63,7 +63,7 @@ {% trans "IP Address Blocklist" %}
  • - {% url 'settings-link-domain' status='pending' as url %} + {% url 'settings-link-domain' as url %} {% trans "Link Domains" %}
  • diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 48368038e..5ec072897 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -158,6 +158,11 @@ urlpatterns = [ views.EmailBlocklist.as_view(), name="settings-email-blocks-delete", ), + re_path( + r"^setting/link-domains/?$", + views.LinkDomain.as_view(), + name="settings-link-domain", + ), re_path( r"^setting/link-domains/(?P(pending|approved|blocked))/?$", views.LinkDomain.as_view(), diff --git a/bookwyrm/views/admin/link_domains.py b/bookwyrm/views/admin/link_domains.py index aab6625c9..564ea8966 100644 --- a/bookwyrm/views/admin/link_domains.py +++ b/bookwyrm/views/admin/link_domains.py @@ -17,7 +17,7 @@ from bookwyrm import forms, models class LinkDomain(View): """Moderate links""" - def get(self, request, status): + def get(self, request, status="pending"): """view pending domains""" data = { "domains": models.LinkDomain.objects.filter(status=status).prefetch_related( From 274631815281218bda31c322af70457eff1aac34 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 15:47:40 -0800 Subject: [PATCH 51/69] Uses datalist for autocomplete suggestions --- bookwyrm/static/css/bookwyrm.css | 7 ------- bookwyrm/static/js/autocomplete.js | 12 ++---------- bookwyrm/templates/book/file_link_modal.html | 3 ++- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 72d39a7ec..92ddd294d 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -606,13 +606,6 @@ details[open].details-panel summary .details-close { right: 1em; } -/** Autocomplete suggestions - ******************************************************************************/ -.autocomplete-suggestions { - position: fixed; - z-index: 1; -} - /** Tooltips ******************************************************************************/ diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index f75948078..df5c890f7 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -21,25 +21,17 @@ // Get suggestions let suggestions = getSuggestions(input.value, mimetypeTrie); - const boxId = input.id + "_suggestions"; + const boxId = input.getAttribute("list"); // Create suggestion box, if needed let suggestionsBox = document.getElementById(boxId); - if (!suggestionsBox) { - suggestionsBox = document.createElement("ul"); - suggestionsBox.id = boxId; - suggestionsBox.classList.add("autocomplete-suggestions", "box"); - - input.insertAdjacentElement("afterend", suggestionsBox); - } - // Clear existing suggestions suggestionsBox.innerHTML = ""; // Populate suggestions box suggestions.forEach(suggestion => { - const suggestionItem = document.createElement("li"); + const suggestionItem = document.createElement("option"); suggestionItem.textContent = suggestion; suggestionsBox.appendChild(suggestionItem); diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 87d358174..48921bb89 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -27,7 +27,8 @@
    - + + {% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
    From f6d6285009dde5eaf8bcd9766271773c48627df7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 16:44:43 -0800 Subject: [PATCH 52/69] Updates trie function --- bookwyrm/static/js/autocomplete.js | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index df5c890f7..b9877b924 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -52,24 +52,22 @@ return []; } - return searchTrie(input, trie); + return searchTrie(trie); } - function searchTrie(output, trie) { - const options = Object.keys(trie); + function searchTrie(trie) { + const options = Object.values(trie); if (!options.length) { - return [output]; + return; + } else if (typeof options[0] == 'string') { + return [options[0]]; } return options.map(option => { - const newTrie = trie[option]; + const newTrie = option; - if (!newTrie) { - return; - } - - return searchTrie(output + option, trie[option]); + return searchTrie(newTrie); }).reduce((prev, next) => prev.concat(next)); } @@ -83,14 +81,11 @@ const mimetypeTrie = { "p": { "d": { - "f": { - "": {}, - "x": {}, - }, + "f": "PDF", }, "n": { - "g": {} + "g": "PNG", }, - } + }, }; From 4202498442e582f85c62e352219ad6ce8a33a753 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 16:53:30 -0800 Subject: [PATCH 53/69] Fixes one option trie case --- bookwyrm/static/js/autocomplete.js | 35 ++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index b9877b924..d2d66b4a6 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -58,15 +58,17 @@ function searchTrie(trie) { const options = Object.values(trie); - if (!options.length) { - return; - } else if (typeof options[0] == 'string') { - return [options[0]]; + if (typeof trie == 'string') { + return [trie]; } return options.map(option => { const newTrie = option; + if (typeof newTrie == 'string') { + return [newTrie]; + } + return searchTrie(newTrie); }).reduce((prev, next) => prev.concat(next)); } @@ -79,13 +81,32 @@ })(); const mimetypeTrie = { + "a": { + "a": { + "c": "AAC", + }, + "z": { + "w": "AZW", + } + }, + "d": "Daisy", + "e": "ePub", + "f": "FLAC", + "h": "HTML", + "m": { + "4": { + "a": "M4A", + "b": "M4B", + }, + "o": "MOBI", + "p": "MP3", + }, + "o": "OGG", "p": { "d": { "f": "PDF", }, - "n": { - "g": "PNG", - }, + "l": "Plaintext", }, }; From 60761b19ba94ae153c3e90fbd27760c9171bc692 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 16:55:30 -0800 Subject: [PATCH 54/69] Run prettier --- bookwyrm/static/js/autocomplete.js | 77 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index d2d66b4a6..f8a982358 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -1,5 +1,5 @@ -(function() { - 'use strict'; +(function () { + "use strict"; /** * Suggest a completion as a user types @@ -30,7 +30,7 @@ suggestionsBox.innerHTML = ""; // Populate suggestions box - suggestions.forEach(suggestion => { + suggestions.forEach((suggestion) => { const suggestionItem = document.createElement("option"); suggestionItem.textContent = suggestion; @@ -40,7 +40,7 @@ function getSuggestions(input, trie) { // Follow the trie through the provided input - input.split("").forEach(letter => { + input.split("").forEach((letter) => { trie = trie[letter]; if (!trie) { @@ -58,55 +58,54 @@ function searchTrie(trie) { const options = Object.values(trie); - if (typeof trie == 'string') { + if (typeof trie == "string") { return [trie]; } - return options.map(option => { - const newTrie = option; + return options + .map((option) => { + const newTrie = option; - if (typeof newTrie == 'string') { - return [newTrie]; - } + if (typeof newTrie == "string") { + return [newTrie]; + } - return searchTrie(newTrie); - }).reduce((prev, next) => prev.concat(next)); + return searchTrie(newTrie); + }) + .reduce((prev, next) => prev.concat(next)); } - document - .querySelectorAll('[data-autocomplete]') - .forEach(input => { - input.addEventListener('input', autocomplete); - }); + document.querySelectorAll("[data-autocomplete]").forEach((input) => { + input.addEventListener("input", autocomplete); + }); })(); const mimetypeTrie = { - "a": { - "a": { - "c": "AAC", + a: { + a: { + c: "AAC", + }, + z: { + w: "AZW", }, - "z": { - "w": "AZW", - } }, - "d": "Daisy", - "e": "ePub", - "f": "FLAC", - "h": "HTML", - "m": { - "4": { - "a": "M4A", - "b": "M4B", + d: "Daisy", + e: "ePub", + f: "FLAC", + h: "HTML", + m: { + 4: { + a: "M4A", + b: "M4B", }, - "o": "MOBI", - "p": "MP3", + o: "MOBI", + p: "MP3", }, - "o": "OGG", - "p": { - "d": { - "f": "PDF", + o: "OGG", + p: { + d: { + f: "PDF", }, - "l": "Plaintext", + l: "Plaintext", }, }; - From de1bace8f363ee57d15db8968c9af3efed79f48c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 11 Jan 2022 08:06:52 -0800 Subject: [PATCH 55/69] Updates tests --- bookwyrm/tests/views/admin/test_link_domains.py | 1 + bookwyrm/tests/views/admin/test_reports.py | 10 +++++----- bookwyrm/tests/views/books/test_links.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bookwyrm/tests/views/admin/test_link_domains.py b/bookwyrm/tests/views/admin/test_link_domains.py index 8c972ea10..5d440dc50 100644 --- a/bookwyrm/tests/views/admin/test_link_domains.py +++ b/bookwyrm/tests/views/admin/test_link_domains.py @@ -29,6 +29,7 @@ class LinkDomainViews(TestCase): models.FileLink.objects.create( book=self.book, url="https://beep.com/book/1", + added_by=self.local_user, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 137d17cb0..d0f2e9d91 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -37,7 +37,7 @@ class ReportViews(TestCase): def test_reports_page(self): """there are so many views, this just makes sure it LOADS""" - view = views.Reports.as_view() + view = views.ReportsAdmin.as_view() request = self.factory.get("") request.user = self.local_user request.user.is_superuser = True @@ -49,7 +49,7 @@ class ReportViews(TestCase): def test_reports_page_with_data(self): """there are so many views, this just makes sure it LOADS""" - view = views.Reports.as_view() + view = views.ReportsAdmin.as_view() request = self.factory.get("") request.user = self.local_user request.user.is_superuser = True @@ -62,7 +62,7 @@ class ReportViews(TestCase): def test_report_page(self): """there are so many views, this just makes sure it LOADS""" - view = views.Report.as_view() + view = views.ReportAdmin.as_view() request = self.factory.get("") request.user = self.local_user request.user.is_superuser = True @@ -76,7 +76,7 @@ class ReportViews(TestCase): def test_report_comment(self): """comment on a report""" - view = views.Report.as_view() + view = views.ReportAdmin.as_view() request = self.factory.post("", {"note": "hi"}) request.user = self.local_user request.user.is_superuser = True @@ -97,7 +97,7 @@ class ReportViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - views.make_report(request) + views.Report.as_view()(request) report = models.Report.objects.get() self.assertEqual(report.reporter, self.local_user) diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index 1961bde00..bdd9aaf42 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -66,7 +66,7 @@ class LinkViews(TestCase): form.data["url"] = "https://www.example.com" form.data["filetype"] = "HTML" form.data["book"] = self.book.id - form.data["added_by"] = self.local_user + form.data["added_by"] = self.local_user.id request = self.factory.post("", form.data) request.user = self.local_user From 2ca41a0b118541dbc520f5c46ab7c5921aed1208 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 09:16:24 -0800 Subject: [PATCH 56/69] Renames add link view --- bookwyrm/tests/views/books/test_links.py | 8 ++++---- bookwyrm/urls.py | 8 ++------ bookwyrm/views/__init__.py | 2 +- bookwyrm/views/books/links.py | 13 ++++--------- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index bdd9aaf42..9e051926e 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -48,9 +48,9 @@ class LinkViews(TestCase): models.SiteSettings.objects.create() - def test_edit_link_page(self): + def test_add_link_page(self): """there are so many views, this just makes sure it LOADS""" - view = views.FileLink.as_view() + view = views.AddFileLink.as_view() request = self.factory.get("") request.user = self.local_user result = view(request, self.book.id) @@ -59,9 +59,9 @@ class LinkViews(TestCase): self.assertEqual(result.status_code, 200) - def test_edit_link_post(self, *_): + def test_add_link_post(self, *_): """there are so many views, this just makes sure it LOADS""" - view = views.FileLink.as_view() + view = views.AddFileLink.as_view() form = forms.FileLinkForm() form.data["url"] = "https://www.example.com" form.data["filetype"] = "HTML" diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 20092106f..e1dd65295 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -168,6 +168,7 @@ urlpatterns = [ views.LinkDomain.as_view(), name="settings-link-domain", ), + # pylint: disable=line-too-long re_path( r"^setting/link-domains/(?P(pending|approved|blocked))/(?P\d+)/?$", views.LinkDomain.as_view(), @@ -468,12 +469,7 @@ urlpatterns = [ views.add_description, name="add-description", ), - re_path(rf"{BOOK_PATH}/filelink/?$", views.FileLink.as_view(), name="file-link"), - re_path( - rf"{BOOK_PATH}/filelink/(?P\d+)/?$", - views.FileLink.as_view(), - name="file-link", - ), + re_path(rf"{BOOK_PATH}/filelink/?$", views.AddFileLink.as_view(), name="file-link"), re_path(r"^resolve-book/?$", views.resolve_book, name="resolve-book"), re_path(r"^switch-edition/?$", views.switch_edition, name="switch-edition"), re_path( diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index eb9eefe2e..781bc52a9 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -37,7 +37,7 @@ from .books.books import ( from .books.books import update_book_from_remote from .books.edit_book import EditBook, ConfirmEditBook from .books.editions import Editions, switch_edition -from .books.links import FileLink +from .books.links import AddFileLink # landing from .landing.about import about, privacy, conduct diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index 1b6818bae..e83ba599d 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -7,7 +7,6 @@ from django.views import View from django.utils.decorators import method_decorator from bookwyrm import forms, models -from bookwyrm.activitypub import ActivitypubResponse # pylint: disable=no-self-use @@ -15,18 +14,14 @@ from bookwyrm.activitypub import ActivitypubResponse @method_decorator( permission_required("bookwyrm.edit_book", raise_exception=True), name="dispatch" ) -class FileLink(View): +class AddFileLink(View): """a book! this is the stuff""" - def get(self, request, book_id=None, link_id=None): - """info about a book""" - link = get_object_or_404(models.FileLink, id=link_id) if link_id else None - if not book_id: - return ActivitypubResponse(link.to_activity()) - + def get(self, request, book_id): + """Create link form""" book = get_object_or_404(models.Edition, id=book_id) data = { - "file_link_form": forms.FileLinkForm(instance=link), + "file_link_form": forms.FileLinkForm(), "book": book, } return TemplateResponse(request, "book/file_link_page.html", data) From ebc451fdd23872d696a9ead4951374eecabda2f7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 09:52:26 -0800 Subject: [PATCH 57/69] Edit links view --- bookwyrm/templates/book/edit_links.html | 69 +++++++++++++++++++ bookwyrm/templates/book/file_link_modal.html | 2 +- .../book/link_verification_modal.html | 2 +- bookwyrm/templates/book/links.html | 12 ++-- .../settings/link_domains/link_table.html | 12 +++- bookwyrm/urls.py | 3 +- bookwyrm/views/__init__.py | 2 +- bookwyrm/views/books/links.py | 9 +++ 8 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 bookwyrm/templates/book/edit_links.html diff --git a/bookwyrm/templates/book/edit_links.html b/bookwyrm/templates/book/edit_links.html new file mode 100644 index 000000000..b145ce156 --- /dev/null +++ b/bookwyrm/templates/book/edit_links.html @@ -0,0 +1,69 @@ +{% extends 'layout.html' %} +{% load i18n %} +{% load utilities %} + +{% block title %}{% trans "Edit links" %}{% endblock %} + +{% block content %} + +
    +

    + {% blocktrans with title=book|book_title %} + Links for "{{ title }}" + {% endblocktrans %} +

    +
    + + + +
    +
    +
    {% trans "URL" %}{% trans "Added by" %} {% trans "Filetype" %} {% trans "Book" %}
    {{ link.url }} + @{{ link.added_by|username }} + {% if link.filelink.filetype %} {{ link.filelink.filetype }} From 78dd5caf9f40517709daf64506bb18417e24ad19 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 10 Jan 2022 14:55:10 -0800 Subject: [PATCH 47/69] Allow users to report spam links --- bookwyrm/forms.py | 2 +- .../migrations/0127_auto_20220110_2211.py | 22 ++++ bookwyrm/models/link.py | 5 +- bookwyrm/models/report.py | 6 +- bookwyrm/static/css/bookwyrm.css | 4 + .../book/link_verification_modal.html | 9 +- bookwyrm/templates/report.html | 10 ++ .../settings/link_domains/link_domains.html | 35 +----- .../settings/link_domains/link_table.html | 36 ++++++ .../templates/settings/reports/report.html | 55 +++++---- .../settings/reports/report_header.html | 22 ++++ .../settings/reports/report_links_table.html | 20 +++ .../settings/reports/report_preview.html | 8 +- .../users/user_moderation_actions.html | 114 +++++++++--------- .../templates/snippets/report_button.html | 2 +- bookwyrm/templates/snippets/report_modal.html | 27 ++++- bookwyrm/urls.py | 19 ++- bookwyrm/views/__init__.py | 6 +- bookwyrm/views/admin/reports.py | 20 +-- bookwyrm/views/report.py | 39 ++++++ 20 files changed, 310 insertions(+), 151 deletions(-) create mode 100644 bookwyrm/migrations/0127_auto_20220110_2211.py create mode 100644 bookwyrm/templates/report.html create mode 100644 bookwyrm/templates/settings/link_domains/link_table.html create mode 100644 bookwyrm/templates/settings/reports/report_header.html create mode 100644 bookwyrm/templates/settings/reports/report_links_table.html create mode 100644 bookwyrm/views/report.py diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index e08f3a3a5..0d27fffef 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -453,7 +453,7 @@ class GroupForm(CustomForm): class ReportForm(CustomForm): class Meta: model = models.Report - fields = ["user", "reporter", "statuses", "note"] + fields = ["user", "reporter", "statuses", "links", "note"] class EmailBlocklistForm(CustomForm): diff --git a/bookwyrm/migrations/0127_auto_20220110_2211.py b/bookwyrm/migrations/0127_auto_20220110_2211.py new file mode 100644 index 000000000..e18be29e6 --- /dev/null +++ b/bookwyrm/migrations/0127_auto_20220110_2211.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.10 on 2022-01-10 22:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0126_filelink_link_linkdomain"), + ] + + operations = [ + migrations.RemoveConstraint( + model_name="report", + name="self_report", + ), + migrations.AddField( + model_name="report", + name="links", + field=models.ManyToManyField(blank=True, to="bookwyrm.Link"), + ), + ] diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 3e21642f2..be7c104f0 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -16,10 +16,7 @@ class Link(ActivitypubMixin, BookWyrmModel): url = fields.URLField(max_length=255, activitypub_field="href") added_by = fields.ForeignKey( - "User", - on_delete=models.SET_NULL, - null=True, - activitypub_field="attributedTo" + "User", on_delete=models.SET_NULL, null=True, activitypub_field="attributedTo" ) domain = models.ForeignKey( "LinkDomain", diff --git a/bookwyrm/models/report.py b/bookwyrm/models/report.py index 636817cb2..4910a4e08 100644 --- a/bookwyrm/models/report.py +++ b/bookwyrm/models/report.py @@ -13,14 +13,12 @@ class Report(BookWyrmModel): note = models.TextField(null=True, blank=True) user = models.ForeignKey("User", on_delete=models.PROTECT) statuses = models.ManyToManyField("Status", blank=True) + links = models.ManyToManyField("Link", blank=True) resolved = models.BooleanField(default=False) class Meta: - """don't let users report themselves""" + """set order by default""" - constraints = [ - models.CheckConstraint(check=~Q(reporter=F("user")), name="self_report") - ] ordering = ("-created_date",) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 4d960734e..92ddd294d 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -720,6 +720,10 @@ ol.ordered-list li::before { } } +.overflow-wrap-anywhere { + overflow-wrap: anywhere; +} + /* Threads ******************************************************************************/ diff --git a/bookwyrm/templates/book/link_verification_modal.html b/bookwyrm/templates/book/link_verification_modal.html index ed7dca8e6..eab8987b8 100644 --- a/bookwyrm/templates/book/link_verification_modal.html +++ b/bookwyrm/templates/book/link_verification_modal.html @@ -9,7 +9,8 @@ {% block modal-body %} {% blocktrans trimmed with link_url=link.url %} -This link is taking you to {{ link_url }}. Is that where you'd like to go? +This link is taking you to: {{ link_url }}.
    +Is that where you'd like to go? {% endblocktrans %} {% endblock %} @@ -19,4 +20,10 @@ This link is taking you to {{ link_url }}. Is that where you'd like {% trans "Continue" %} +{% if request.user.is_authenticated %} + +{% endif %} + {% endblock %} diff --git a/bookwyrm/templates/report.html b/bookwyrm/templates/report.html new file mode 100644 index 000000000..686401ebe --- /dev/null +++ b/bookwyrm/templates/report.html @@ -0,0 +1,10 @@ +{% extends "layout.html" %} +{% load i18n %} + +{% block title %} +{% trans "Report" %} +{% endblock %} + +{% block content %} +{% include "snippets/report_modal.html" with user=user active=True static=True %} +{% endblock %} diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index 83190029c..3f2d60976 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -1,5 +1,4 @@ {% extends 'settings/layout.html' %} -{% load humanize %} {% load i18n %} {% load utilities %} @@ -32,7 +31,7 @@ {% for domain in domains %} {% join "domain" domain.id as domain_modal %} -
    +

    @@ -58,37 +57,7 @@
    - - - - - - - - {% for link in domain.links.all|slice:10 %} - - - - - - - - {% endfor %} -
    {% trans "URL" %}{% trans "Added by" %}{% trans "Filetype" %}{% trans "Book" %}
    - {{ link.url }} - - @{{ link.added_by|username }} - - {% if link.filelink.filetype %} - {{ link.filelink.filetype }} - {% endif %} - - {% if link.filelink.filetype %} - {% with book=link.filelink.book %} - {% include "snippets/book_titleby.html" with book=book %} - {% endwith %} - {% endif %} -
    + {% include "settings/link_domains/link_table.html" with links=domain.links.all|slice:10 %}

    diff --git a/bookwyrm/templates/settings/link_domains/link_table.html b/bookwyrm/templates/settings/link_domains/link_table.html new file mode 100644 index 000000000..680132fdf --- /dev/null +++ b/bookwyrm/templates/settings/link_domains/link_table.html @@ -0,0 +1,36 @@ +{% load i18n %} +{% load utilities %} + + + + + + + + {% block additional_headers %}{% endblock %} + + {% for link in links%} + + + + + + + {% block additional_data %}{% endblock %} + + {% endfor %} +
    {% trans "URL" %}{% trans "Added by" %}{% trans "Filetype" %}{% trans "Book" %}
    + {{ link.url }} + + @{{ link.added_by|username }} + + {% if link.filelink.filetype %} + {{ link.filelink.filetype }} + {% endif %} + + {% if link.filelink.filetype %} + {% with book=link.filelink.book %} + {% include "snippets/book_titleby.html" with book=book %} + {% endwith %} + {% endif %} +
    diff --git a/bookwyrm/templates/settings/reports/report.html b/bookwyrm/templates/settings/reports/report.html index 37593f3cc..84fafb143 100644 --- a/bookwyrm/templates/settings/reports/report.html +++ b/bookwyrm/templates/settings/reports/report.html @@ -2,10 +2,12 @@ {% load i18n %} {% load humanize %} -{% block title %}{% blocktrans with report_id=report.id username=report.user.username %}Report #{{ report_id }}: {{ username }}{% endblocktrans %}{% endblock %} +{% block title %} +{% include "settings/reports/report_header.html" with report=report %} +{% endblock %} {% block header %} -{% blocktrans with report_id=report.id username=report.user.username %}Report #{{ report_id }}: {{ username }}{% endblocktrans %} +{% include "settings/reports/report_header.html" with report=report %}
    {% trans "Back to reports" %} {% endblock %} @@ -15,6 +17,36 @@ {% include 'settings/reports/report_preview.html' with report=report %}
    +{% if report.statuses.exists %} +
    +

    {% trans "Reported statuses" %}

    +
      + {% for status in report.statuses.select_subclasses.all %} +
    • + {% if status.deleted %} + {% trans "Status has been deleted" %} + {% else %} + {% include 'snippets/status/status.html' with status=status moderation_mode=True %} + {% endif %} +
    • + {% endfor %} +
    +
    +{% endif %} + +{% if report.links.exists %} +
    +

    {% trans "Reported links" %}

    +
    +
    +
    + {% include "settings/reports/report_links_table.html" with links=report.links.all %} +
    +
    +
    +
    +{% endif %} + {% include 'settings/users/user_info.html' with user=report.user %} {% include 'settings/users/user_moderation_actions.html' with user=report.user %} @@ -41,23 +73,4 @@
    - -
    -

    {% trans "Reported statuses" %}

    - {% if not report.statuses.exists %} - {% trans "No statuses reported" %} - {% else %} -
      - {% for status in report.statuses.select_subclasses.all %} -
    • - {% if status.deleted %} - {% trans "Status has been deleted" %} - {% else %} - {% include 'snippets/status/status.html' with status=status moderation_mode=True %} - {% endif %} -
    • - {% endfor %} -
    - {% endif %} -
    {% endblock %} diff --git a/bookwyrm/templates/settings/reports/report_header.html b/bookwyrm/templates/settings/reports/report_header.html new file mode 100644 index 000000000..d76db1048 --- /dev/null +++ b/bookwyrm/templates/settings/reports/report_header.html @@ -0,0 +1,22 @@ +{% load i18n %} +{% load utilities %} + +{% if report.statuses.exists %} + +{% blocktrans trimmed with report_id=report.id username=report.user|username %} +Report #{{ report_id }}: Status posted by @{{ username }} +{% endblocktrans %} + +{% elif report.links.exists %} + +{% blocktrans trimmed with report_id=report.id username=report.user|username %} +Report #{{ report_id }}: Link added by @{{ username }} +{% endblocktrans %} + +{% else %} + +{% blocktrans trimmed with report_id=report.id username=report.user|username %} +Report #{{ report_id }}: User @{{ username }} +{% endblocktrans %} + +{% endif %} diff --git a/bookwyrm/templates/settings/reports/report_links_table.html b/bookwyrm/templates/settings/reports/report_links_table.html new file mode 100644 index 000000000..b0ebf73a5 --- /dev/null +++ b/bookwyrm/templates/settings/reports/report_links_table.html @@ -0,0 +1,20 @@ +{% extends "settings/link_domains/link_table.html" %} +{% load i18n %} + +{% block additional_headers %} +
    {% trans "Domain" %}{% trans "Actions" %} + + {{ link.domain.domain }} + + +
    + +
    +
    + + + + + + + + {% for link in book.file_links.all %} + + + + + + + + {% endfor %} + {% if not book.file_links.exists %} + + + + {% endif %} +
    {% trans "URL" %}{% trans "Added by" %}{% trans "Filetype" %}{% trans "Domain" %}{% trans "Actions" %}
    + {{ link.url }} + + {{ link.added_by.display_name }} + + {{ link.filelink.filetype }} + + {{ link.domain.name }} ({{ link.domain.get_status_display }}) +

    + {% trans "Report spam" %} +

    +
    + +
    {% trans "No links available for this book." %}
    +

    + + +{% endblock %} diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_link_modal.html index 379f1a077..fc8b90597 100644 --- a/bookwyrm/templates/book/file_link_modal.html +++ b/bookwyrm/templates/book/file_link_modal.html @@ -6,7 +6,7 @@ {% endblock %} {% block modal-form-open %} -
    + {% endblock %} {% block modal-body %} diff --git a/bookwyrm/templates/book/link_verification_modal.html b/bookwyrm/templates/book/link_verification_modal.html index eab8987b8..1d53c1ef2 100644 --- a/bookwyrm/templates/book/link_verification_modal.html +++ b/bookwyrm/templates/book/link_verification_modal.html @@ -22,7 +22,7 @@ Is that where you'd like to go? {% if request.user.is_authenticated %} {% endif %} diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/links.html index f87d56815..ef2c0a402 100644 --- a/bookwyrm/templates/book/links.html +++ b/bookwyrm/templates/book/links.html @@ -10,8 +10,8 @@
    {% if can_edit_book %}
    - {% url 'file-link' book.id as fallback_url %} - + + {% csrf_token %} + + {% endfor %} @@ -64,6 +67,16 @@ {% endif %}
    + + {% url 'file-link-add' book.id as fallback_url %} +
    + +
    {% endblock %} diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/links.html index ef2c0a402..c77e21464 100644 --- a/bookwyrm/templates/book/links.html +++ b/bookwyrm/templates/book/links.html @@ -11,13 +11,15 @@ {% if can_edit_book %}
    {% url 'file-link-add' book.id as fallback_url %} - + +
    {% endif %}
    diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index ace7f2d02..990601490 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -469,8 +469,19 @@ urlpatterns = [ views.add_description, name="add-description", ), - re_path(rf"{BOOK_PATH}/filelink/?$", views.BookFileLinks.as_view(), name="file-link"), - re_path(rf"{BOOK_PATH}/filelink/add/?$", views.AddFileLink.as_view(), name="file-link-add"), + re_path( + rf"{BOOK_PATH}/filelink/?$", views.BookFileLinks.as_view(), name="file-link" + ), + re_path( + rf"{BOOK_PATH}/filelink/(?P\d+)/delete/?$", + views.BookFileLinks.as_view(), + name="file-link", + ), + re_path( + rf"{BOOK_PATH}/filelink/add/?$", + views.AddFileLink.as_view(), + name="file-link-add", + ), re_path(r"^resolve-book/?$", views.resolve_book, name="resolve-book"), re_path(r"^switch-edition/?$", views.switch_edition, name="switch-edition"), re_path( diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index da4fa5edf..e10e87512 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -18,6 +18,12 @@ class BookFileLinks(View): book = get_object_or_404(models.Edition, id=book_id) return TemplateResponse(request, "book/edit_links.html", {"book": book}) + def post(self, request, book_id, link_id): + """delete link""" + link = get_object_or_404(models.FileLink, id=link_id, book=book_id) + link.delete() + return self.get(request, book_id) + @method_decorator(login_required, name="dispatch") @method_decorator( From c08b9e61c428bcf8adcff5cbcc0eff6630ec16ec Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 11:34:44 -0800 Subject: [PATCH 59/69] Fixes book link in table --- bookwyrm/templates/settings/link_domains/link_table.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/settings/link_domains/link_table.html b/bookwyrm/templates/settings/link_domains/link_table.html index 0c7763b65..62fa17ee2 100644 --- a/bookwyrm/templates/settings/link_domains/link_table.html +++ b/bookwyrm/templates/settings/link_domains/link_table.html @@ -26,7 +26,7 @@ {% if link.filelink.book %} {% with book=link.filelink.book %} - {% include "snippets/book_titleby.html" with book=book %} + {% include "snippets/book_titleby.html" with book=book %} {% endwith %} {% endif %} From dedcbda2d808cfa9495760373fdd03a0931b57c2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 15:40:42 -0800 Subject: [PATCH 60/69] Adds inbox test --- .../tests/views/inbox/test_inbox_update.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 052b47c4b..43b18946b 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -6,6 +6,7 @@ from unittest.mock import patch from django.test import TestCase from bookwyrm import models, views +from bookwyrm.activitypub.base_activity import set_related_field # pylint: disable=too-many-public-methods @@ -147,6 +148,46 @@ class InboxUpdate(TestCase): self.assertEqual(book.title, "Piranesi") self.assertEqual(book.last_edited_by, self.remote_user) + def test_update_edition_links(self): + """add links to edition""" + datafile = pathlib.Path(__file__).parent.joinpath("../../data/bw_edition.json") + bookdata = json.loads(datafile.read_bytes()) + del bookdata["authors"] + # pylint: disable=line-too-long + link_data = { + "href": "https://openlibrary.org/books/OL11645413M/Queen_Victoria/daisy", + "mediaType": "Daisy", + "attributedTo": self.remote_user.remote_id + } + bookdata["fileLinks"] = [link_data] + + models.Work.objects.create( + title="Test Work", remote_id="https://bookwyrm.social/book/5988" + ) + book = models.Edition.objects.create( + title="Test Book", remote_id="https://bookwyrm.social/book/5989" + ) + self.assertFalse(book.file_links.exists()) + + with patch("bookwyrm.activitypub.base_activity.set_related_field.delay") as mock: + views.inbox.activity_task( + { + "type": "Update", + "to": [], + "cc": [], + "actor": "hi", + "id": "sdkjf", + "object": bookdata, + } + ) + args = mock.call_args[0] + self.assertEqual(args[0], "FileLink") + self.assertEqual(args[1], "Edition") + self.assertEqual(args[2], "book") + self.assertEqual(args[3], book.remote_id) + self.assertEqual(args[4], link_data) + # idk how to test that related name works, because of the transaction + def test_update_work(self): """update an existing edition""" datafile = pathlib.Path(__file__).parent.joinpath("../../data/bw_work.json") From 5fcdc284cea75f4ef69fd144acd4accb036a4aef Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 16:41:23 -0800 Subject: [PATCH 61/69] Removes duplicate atomic block --- bookwyrm/activitypub/base_activity.py | 51 +++++++++++++-------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 57244484a..4894452de 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -208,35 +208,34 @@ def set_related_field( model = apps.get_model(f"bookwyrm.{model_name}", require_ready=True) origin_model = apps.get_model(f"bookwyrm.{origin_model_name}", require_ready=True) - with transaction.atomic(): - if isinstance(data, str): - existing = model.find_existing_by_remote_id(data) - if existing: - data = existing.to_activity() - else: - data = get_data(data) - activity = model.activity_serializer(**data) + if isinstance(data, str): + existing = model.find_existing_by_remote_id(data) + if existing: + data = existing.to_activity() + else: + data = get_data(data) + activity = model.activity_serializer(**data) - # this must exist because it's the object that triggered this function - instance = origin_model.find_existing_by_remote_id(related_remote_id) - if not instance: - raise ValueError(f"Invalid related remote id: {related_remote_id}") + # this must exist because it's the object that triggered this function + instance = origin_model.find_existing_by_remote_id(related_remote_id) + if not instance: + raise ValueError(f"Invalid related remote id: {related_remote_id}") - # set the origin's remote id on the activity so it will be there when - # the model instance is created - # edition.parentWork = instance, for example - model_field = getattr(model, related_field_name) - if hasattr(model_field, "activitypub_field"): - setattr( - activity, getattr(model_field, "activitypub_field"), instance.remote_id - ) - item = activity.to_model() + # set the origin's remote id on the activity so it will be there when + # the model instance is created + # edition.parentWork = instance, for example + model_field = getattr(model, related_field_name) + if hasattr(model_field, "activitypub_field"): + setattr( + activity, getattr(model_field, "activitypub_field"), instance.remote_id + ) + item = activity.to_model() - # if the related field isn't serialized (attachments on Status), then - # we have to set it post-creation - if not hasattr(model_field, "activitypub_field"): - setattr(item, related_field_name, instance) - item.save() + # if the related field isn't serialized (attachments on Status), then + # we have to set it post-creation + if not hasattr(model_field, "activitypub_field"): + setattr(item, related_field_name, instance) + item.save() def get_model_from_type(activity_type): From 262e641c792ba6d123bf925ce74de9dabb7837c4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 16:46:14 -0800 Subject: [PATCH 62/69] Creates link template subdirectory --- bookwyrm/templates/book/book.html | 2 +- .../add_link_modal.html} | 0 bookwyrm/templates/book/{ => file_links}/edit_links.html | 0 .../templates/book/{ => file_links}/file_link_page.html | 2 +- bookwyrm/templates/book/{ => file_links}/links.html | 4 ++-- .../verification_modal.html} | 0 bookwyrm/views/books/links.py | 6 +++--- 7 files changed, 7 insertions(+), 7 deletions(-) rename bookwyrm/templates/book/{file_link_modal.html => file_links/add_link_modal.html} (100%) rename bookwyrm/templates/book/{ => file_links}/edit_links.html (100%) rename bookwyrm/templates/book/{ => file_links}/file_link_page.html (56%) rename bookwyrm/templates/book/{ => file_links}/links.html (90%) rename bookwyrm/templates/book/{link_verification_modal.html => file_links/verification_modal.html} (100%) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 6d81290e1..c8c78e0e9 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -375,7 +375,7 @@ {% endif %}
    - {% include "book/links.html" %} + {% include "book/file_links/links.html" %}
    diff --git a/bookwyrm/templates/book/file_link_modal.html b/bookwyrm/templates/book/file_links/add_link_modal.html similarity index 100% rename from bookwyrm/templates/book/file_link_modal.html rename to bookwyrm/templates/book/file_links/add_link_modal.html diff --git a/bookwyrm/templates/book/edit_links.html b/bookwyrm/templates/book/file_links/edit_links.html similarity index 100% rename from bookwyrm/templates/book/edit_links.html rename to bookwyrm/templates/book/file_links/edit_links.html diff --git a/bookwyrm/templates/book/file_link_page.html b/bookwyrm/templates/book/file_links/file_link_page.html similarity index 56% rename from bookwyrm/templates/book/file_link_page.html rename to bookwyrm/templates/book/file_links/file_link_page.html index 26a8d89d3..902057af2 100644 --- a/bookwyrm/templates/book/file_link_page.html +++ b/bookwyrm/templates/book/file_links/file_link_page.html @@ -6,5 +6,5 @@ {% endblock %} {% block content %} -{% include "book/file_link_modal.html" with book=book active=True static=True id="file-link" %} +{% include "book/file_links/add_link_modal.html" with book=book active=True static=True id="file-link" %} {% endblock %} diff --git a/bookwyrm/templates/book/links.html b/bookwyrm/templates/book/file_links/links.html similarity index 90% rename from bookwyrm/templates/book/links.html rename to bookwyrm/templates/book/file_links/links.html index c77e21464..10a6da2f2 100644 --- a/bookwyrm/templates/book/links.html +++ b/bookwyrm/templates/book/file_links/links.html @@ -35,7 +35,7 @@ {% for link in links.all %} {% join "verify" link.id as verify_modal %} -{% include "book/link_verification_modal.html" with id=verify_modal %} +{% include "book/file_links/verification_modal.html" with id=verify_modal %} {% endfor %} {% else %} {% trans "No links available" %} @@ -46,7 +46,7 @@ {% trans "Edit links" %} -{% include 'book/file_link_modal.html' with book=book id="add-links" %} +{% include 'book/file_links/add_link_modal.html' with book=book id="add-links" %} {% endif %} {% endif %} diff --git a/bookwyrm/templates/book/link_verification_modal.html b/bookwyrm/templates/book/file_links/verification_modal.html similarity index 100% rename from bookwyrm/templates/book/link_verification_modal.html rename to bookwyrm/templates/book/file_links/verification_modal.html diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index e10e87512..9dca41e46 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -16,7 +16,7 @@ class BookFileLinks(View): def get(self, request, book_id): """view links""" book = get_object_or_404(models.Edition, id=book_id) - return TemplateResponse(request, "book/edit_links.html", {"book": book}) + return TemplateResponse(request, "book/file_links/edit_links.html", {"book": book}) def post(self, request, book_id, link_id): """delete link""" @@ -39,7 +39,7 @@ class AddFileLink(View): "file_link_form": forms.FileLinkForm(), "book": book, } - return TemplateResponse(request, "book/file_link_page.html", data) + return TemplateResponse(request, "book/file_links/file_link_page.html", data) @transaction.atomic def post(self, request, book_id, link_id=None): @@ -49,7 +49,7 @@ class AddFileLink(View): form = forms.FileLinkForm(request.POST, instance=link) if not form.is_valid(): data = {"file_link_form": form, "book": book} - return TemplateResponse(request, "book/file_link_page.html", data) + return TemplateResponse(request, "book/file_links/file_link_page.html", data) link = form.save() book.file_links.add(link) From 34635b0c3fad836df0d044aa3ad777f4e4e41d16 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:02:30 -0800 Subject: [PATCH 63/69] Select trie based on data attr --- bookwyrm/static/js/autocomplete.js | 101 +++++++++++++----- .../book/file_links/add_link_modal.html | 13 ++- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index f8a982358..bb15f6220 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -19,7 +19,9 @@ const input = event.target; // Get suggestions - let suggestions = getSuggestions(input.value, mimetypeTrie); + let trie = tries[input.getAttribute("data-autocomplete")]; + + let suggestions = getSuggestions(input.value, trie); const boxId = input.getAttribute("list"); @@ -80,32 +82,83 @@ }); })(); -const mimetypeTrie = { - a: { +const tries = {"mimetype": { a: { - c: "AAC", + a: { + c: "AAC", + }, + z: { + w: "AZW", + }, }, - z: { - w: "AZW", - }, - }, - d: "Daisy", - e: "ePub", - f: "FLAC", - h: "HTML", - m: { - 4: { - a: "M4A", - b: "M4B", - }, - o: "MOBI", - p: "MP3", - }, - o: "OGG", - p: { d: { - f: "PDF", + a: { + i: { + s: { + y: "Daisy", + }, + }, + }, + }, + e: { + p: { + u: { + b: "ePub", + }, + }, + }, + f: { + l: { + a: { + c: "FLAC", + }, + }, + }, + h: { + t: { + m: { + l: "HTML", + }, + }, + }, + m: { + 4: { + a: "M4A", + b: "M4B", + }, + o: { + b: { + i: "MOBI", + }, + }, + p: { + 3: "MP3", + }, + }, + o: { + g: { + g: "OGG", + }, + }, + p: { + d: { + f: "PDF", + }, + l: { + a: { + i: { + n: { + t: { + e: { + x: { + t: "Plaintext", + }, + }, + }, + }, + }, + }, + }, }, - l: "Plaintext", }, }; diff --git a/bookwyrm/templates/book/file_links/add_link_modal.html b/bookwyrm/templates/book/file_links/add_link_modal.html index 2965142bd..dfc222ee9 100644 --- a/bookwyrm/templates/book/file_links/add_link_modal.html +++ b/bookwyrm/templates/book/file_links/add_link_modal.html @@ -27,7 +27,18 @@
    - + {% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
    From 80efd5888165dc2ec733e68f8d3cd2d04dddc34a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:06:36 -0800 Subject: [PATCH 64/69] Javascript file in correct template --- bookwyrm/templates/book/book.html | 1 + bookwyrm/templates/book/file_links/file_link_page.html | 5 +++++ bookwyrm/templates/layout.html | 1 - 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index c8c78e0e9..f6d9929dd 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -386,4 +386,5 @@ {% block scripts %} + {% endblock %} diff --git a/bookwyrm/templates/book/file_links/file_link_page.html b/bookwyrm/templates/book/file_links/file_link_page.html index 902057af2..00efe5089 100644 --- a/bookwyrm/templates/book/file_links/file_link_page.html +++ b/bookwyrm/templates/book/file_links/file_link_page.html @@ -1,5 +1,6 @@ {% extends 'layout.html' %} {% load i18n %} +{% load static %} {% block title %} {% trans "File Links" %} @@ -8,3 +9,7 @@ {% block content %} {% include "book/file_links/add_link_modal.html" with book=book active=True static=True id="file-link" %} {% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index fd9e43b86..43e8eb227 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -264,7 +264,6 @@ - {% block scripts %}{% endblock %} From fc06f0cdd122c7ce003bb85b8e42b68a76b6a112 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:08:10 -0800 Subject: [PATCH 65/69] Avoid console error --- bookwyrm/static/js/autocomplete.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index bb15f6220..0ba3e2172 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -43,11 +43,11 @@ function getSuggestions(input, trie) { // Follow the trie through the provided input input.split("").forEach((letter) => { - trie = trie[letter]; - if (!trie) { return; } + + trie = trie[letter]; }); if (!trie) { From d1183fd00335a4013ca6ce80fec5649f4aa632ee Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:11:24 -0800 Subject: [PATCH 66/69] Python formatting --- bookwyrm/activitypub/base_activity.py | 4 +--- bookwyrm/tests/views/inbox/test_inbox_update.py | 6 ++++-- bookwyrm/views/books/links.py | 8 ++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 4894452de..15ca5a938 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -226,9 +226,7 @@ def set_related_field( # edition.parentWork = instance, for example model_field = getattr(model, related_field_name) if hasattr(model_field, "activitypub_field"): - setattr( - activity, getattr(model_field, "activitypub_field"), instance.remote_id - ) + setattr(activity, getattr(model_field, "activitypub_field"), instance.remote_id) item = activity.to_model() # if the related field isn't serialized (attachments on Status), then diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 43b18946b..963742c83 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -157,7 +157,7 @@ class InboxUpdate(TestCase): link_data = { "href": "https://openlibrary.org/books/OL11645413M/Queen_Victoria/daisy", "mediaType": "Daisy", - "attributedTo": self.remote_user.remote_id + "attributedTo": self.remote_user.remote_id, } bookdata["fileLinks"] = [link_data] @@ -169,7 +169,9 @@ class InboxUpdate(TestCase): ) self.assertFalse(book.file_links.exists()) - with patch("bookwyrm.activitypub.base_activity.set_related_field.delay") as mock: + with patch( + "bookwyrm.activitypub.base_activity.set_related_field.delay" + ) as mock: views.inbox.activity_task( { "type": "Update", diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index 9dca41e46..989ca9c49 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -16,7 +16,9 @@ class BookFileLinks(View): def get(self, request, book_id): """view links""" book = get_object_or_404(models.Edition, id=book_id) - return TemplateResponse(request, "book/file_links/edit_links.html", {"book": book}) + return TemplateResponse( + request, "book/file_links/edit_links.html", {"book": book} + ) def post(self, request, book_id, link_id): """delete link""" @@ -49,7 +51,9 @@ class AddFileLink(View): form = forms.FileLinkForm(request.POST, instance=link) if not form.is_valid(): data = {"file_link_form": form, "book": book} - return TemplateResponse(request, "book/file_links/file_link_page.html", data) + return TemplateResponse( + request, "book/file_links/file_link_page.html", data + ) link = form.save() book.file_links.add(link) From e6355f76de415d832d6773043307e7b7b01180c6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:14:59 -0800 Subject: [PATCH 67/69] Adds merge migration --- ...26_auto_20220112_2315_0127_auto_20220110_2211.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0128_merge_0126_auto_20220112_2315_0127_auto_20220110_2211.py diff --git a/bookwyrm/migrations/0128_merge_0126_auto_20220112_2315_0127_auto_20220110_2211.py b/bookwyrm/migrations/0128_merge_0126_auto_20220112_2315_0127_auto_20220110_2211.py new file mode 100644 index 000000000..dc700e99c --- /dev/null +++ b/bookwyrm/migrations/0128_merge_0126_auto_20220112_2315_0127_auto_20220110_2211.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.10 on 2022-01-13 01:14 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0126_auto_20220112_2315"), + ("bookwyrm", "0127_auto_20220110_2211"), + ] + + operations = [] From 2fbbdbc06a08a2b89f98ca4e7fd20362ffd52f59 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 12 Jan 2022 17:19:34 -0800 Subject: [PATCH 68/69] Runs prettier --- bookwyrm/static/js/autocomplete.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index 0ba3e2172..896100832 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -82,7 +82,8 @@ }); })(); -const tries = {"mimetype": { +const tries = { + mimetype: { a: { a: { c: "AAC", From d95830037ab8ecc0a41df6ee8f3729c4a4892105 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 13 Jan 2022 10:59:52 -0800 Subject: [PATCH 69/69] Adds admin notice --- bookwyrm/templates/settings/dashboard/dashboard.html | 11 +++++++++++ bookwyrm/views/admin/dashboard.py | 3 +++ 2 files changed, 14 insertions(+) diff --git a/bookwyrm/templates/settings/dashboard/dashboard.html b/bookwyrm/templates/settings/dashboard/dashboard.html index f320028b7..65c666a67 100644 --- a/bookwyrm/templates/settings/dashboard/dashboard.html +++ b/bookwyrm/templates/settings/dashboard/dashboard.html @@ -48,6 +48,17 @@ {% endif %} + {% if pending_domains %} + + {% endif %} {% if not site.allow_registration and site.allow_invite_requests and invite_requests %}