From 901e7f69d436e66de2e664c645c9521e7bbbe9d1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 12 Apr 2021 14:23:51 -0700 Subject: [PATCH 1/4] Allow admins to upload domain blocklists Fixes #804 --- bookwyrm/templates/import.html | 2 +- bookwyrm/templates/settings/edit_server.html | 17 ++++- .../templates/settings/federated_server.html | 3 +- bookwyrm/templates/settings/federation.html | 2 +- .../templates/settings/server_blocklist.html | 67 +++++++++++++++++++ bookwyrm/urls.py | 5 ++ bookwyrm/views/__init__.py | 3 +- bookwyrm/views/federation.py | 35 ++++++++++ 8 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 bookwyrm/templates/settings/server_blocklist.html diff --git a/bookwyrm/templates/import.html b/bookwyrm/templates/import.html index a5405131..239b6914 100644 --- a/bookwyrm/templates/import.html +++ b/bookwyrm/templates/import.html @@ -26,7 +26,7 @@
- + {{ import_form.csv_file }}
diff --git a/bookwyrm/templates/settings/edit_server.html b/bookwyrm/templates/settings/edit_server.html index 6ae22789..c5702c84 100644 --- a/bookwyrm/templates/settings/edit_server.html +++ b/bookwyrm/templates/settings/edit_server.html @@ -9,6 +9,19 @@ {% block panel %} +
+ +
+
{% csrf_token %}
@@ -24,8 +37,8 @@
diff --git a/bookwyrm/templates/settings/federated_server.html b/bookwyrm/templates/settings/federated_server.html index 6996557d..14b78af0 100644 --- a/bookwyrm/templates/settings/federated_server.html +++ b/bookwyrm/templates/settings/federated_server.html @@ -1,6 +1,7 @@ {% extends 'settings/admin_layout.html' %} {% block title %}{{ server.server_name }}{% endblock %} {% load i18n %} +{% load bookwyrm_tags %} {% block header %} {{ server.server_name }} @@ -81,7 +82,7 @@ {% if server.notes %} -

{{ server.notes }}

+

{{ server.notes|to_markdown|safe }}

{% endif %} {% csrf_token %} diff --git a/bookwyrm/templates/settings/federation.html b/bookwyrm/templates/settings/federation.html index 99afb541..9eb0f8b1 100644 --- a/bookwyrm/templates/settings/federation.html +++ b/bookwyrm/templates/settings/federation.html @@ -5,7 +5,7 @@ {% block header %}{% trans "Federated Servers" %}{% endblock %} {% block edit-button %} - + {% trans "Add server" %} diff --git a/bookwyrm/templates/settings/server_blocklist.html b/bookwyrm/templates/settings/server_blocklist.html new file mode 100644 index 00000000..0de49acd --- /dev/null +++ b/bookwyrm/templates/settings/server_blocklist.html @@ -0,0 +1,67 @@ +{% extends 'settings/admin_layout.html' %} +{% load i18n %} +{% block title %}{% trans "Add server" %}{% endblock %} + +{% block header %} +{% trans "Import Blocklist" %} +{% trans "Back to server list" %} +{% endblock %} + +{% block panel %} + +
+ +
+ +{% if succeeded and not failed %} +

{% trans "Success!" %}

+{% elif succeeded or failed %} +
+ {% if succeeded %} +

{% trans "Successfully blocked:" %} {{ succeeded }}

+ {% endif %} +

{% trans "Failed:" %}

+
    + {% for item in failed %} +
  • +
    +{{ item }}
    +
    +
  • + {% endfor %} +
+
+{% endif %} + + + {% csrf_token %} +
+ + + +
+ + +
+ +{% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index c5c52800..cf3f877b 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -83,6 +83,11 @@ urlpatterns = [ views.AddFederatedServer.as_view(), name="settings-add-federated-server", ), + re_path( + r"^settings/federation/import/?$", + views.ImportServerBlocklist.as_view(), + name="settings-import-blocklist", + ), re_path( r"^settings/invites/?$", views.ManageInvites.as_view(), name="settings-invites" ), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index d7bc4e13..9f8463b4 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -5,7 +5,8 @@ from .block import Block, unblock from .books import Book, EditBook, ConfirmEditBook, Editions from .books import upload_cover, add_description, switch_edition, resolve_book from .directory import Directory -from .federation import Federation, FederatedServer, AddFederatedServer +from .federation import Federation, FederatedServer +from .federation import AddFederatedServer, ImportServerBlocklist from .federation import block_server, unblock_server from .feed import DirectMessage, Feed, Replies, Status from .follow import follow, unfollow diff --git a/bookwyrm/views/federation.py b/bookwyrm/views/federation.py index f34f7d19..b9a7fa85 100644 --- a/bookwyrm/views/federation.py +++ b/bookwyrm/views/federation.py @@ -1,6 +1,8 @@ """ manage federated servers """ +import json from django.contrib.auth.decorators import login_required, permission_required from django.core.paginator import Paginator +from django.db import transaction from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -63,6 +65,39 @@ class AddFederatedServer(View): return redirect("settings-federated-server", server.id) +class ImportServerBlocklist(View): + """ manually add a server """ + + def get(self, request): + """ add server form """ + return TemplateResponse(request, "settings/server_blocklist.html") + + def post(self, request): + """ add a server from the admin panel """ + json_data = json.load( + request.FILES["json_file"] + ) + failed = [] + success_count = 0 + for item in json_data: + server_name = item.get("instance") + if not server_name: + failed.append(item) + continue + info_link = item.get("url") + + with transaction.atomic(): + server, _ = models.FederatedServer.objects.get_or_create( + server_name=server_name, + ) + server.notes = info_link + server.save() + server.block() + success_count += 1 + data = {"failed": failed, "succeeded": success_count} + return TemplateResponse(request, "settings/server_blocklist.html", data) + + @method_decorator(login_required, name="dispatch") @method_decorator( permission_required("bookwyrm.control_federation", raise_exception=True), From a907dfdce7744aeb1bef046acfd17ab67c5e7f88 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 12 Apr 2021 15:08:10 -0700 Subject: [PATCH 2/4] Adds tests for block lists --- bookwyrm/tests/views/test_federation.py | 37 +++++++++++++++++++++++++ bookwyrm/views/federation.py | 5 ++++ 2 files changed, 42 insertions(+) diff --git a/bookwyrm/tests/views/test_federation.py b/bookwyrm/tests/views/test_federation.py index 4dc5d048..b56c2581 100644 --- a/bookwyrm/tests/views/test_federation.py +++ b/bookwyrm/tests/views/test_federation.py @@ -1,5 +1,7 @@ """ test for app action functionality """ +import json from unittest.mock import patch +from django.core.files.uploadedfile import SimpleUploadedFile from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory @@ -127,3 +129,38 @@ class FederationViews(TestCase): self.assertEqual(server.server_name, "remote.server") self.assertEqual(server.application_type, "coolsoft") self.assertEqual(server.status, "blocked") + + def test_import_blocklist(self): + """ load a json file with a list of servers to block """ + server = models.FederatedServer.objects.create(server_name="hi.there.com") + self.remote_user.federated_server = server + self.remote_user.save() + + data = [ + {"instance": "server.name", "url": "https://explanation.url"}, # new server + {"instance": "hi.there.com", "url": "https://explanation.url"}, # existing + {"a": "b"}, # invalid + ] + json.dump(data, open("file.json", "w")) + + view = views.ImportServerBlocklist.as_view() + request = self.factory.post( + "", { + "json_file": SimpleUploadedFile( + "file.json", open("file.json", "rb").read() + ) + } + ) + request.user = self.local_user + request.user.is_superuser = True + + view(request) + server.refresh_from_db() + self.remote_user.refresh_from_db() + + self.assertEqual(models.FederatedServer.objects.count(), 2) + self.assertEqual(server.status, "blocked") + self.assertFalse(self.remote_user.is_active) + created = models.FederatedServer.objects.get(server_name="server.name") + self.assertEqual(created.status, "blocked") + self.assertEqual(created.notes, "https://explanation.url") diff --git a/bookwyrm/views/federation.py b/bookwyrm/views/federation.py index b9a7fa85..25cd212b 100644 --- a/bookwyrm/views/federation.py +++ b/bookwyrm/views/federation.py @@ -65,6 +65,11 @@ class AddFederatedServer(View): return redirect("settings-federated-server", server.id) +@method_decorator(login_required, name="dispatch") +@method_decorator( + permission_required("bookwyrm.control_federation", raise_exception=True), + name="dispatch", +) class ImportServerBlocklist(View): """ manually add a server """ From 822e2e1a931f53a64372be6c8557db180aeaf802 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 12 Apr 2021 15:09:50 -0700 Subject: [PATCH 3/4] Python formatting --- bookwyrm/tests/views/test_federation.py | 5 +++-- bookwyrm/views/federation.py | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bookwyrm/tests/views/test_federation.py b/bookwyrm/tests/views/test_federation.py index b56c2581..2afdd6d3 100644 --- a/bookwyrm/tests/views/test_federation.py +++ b/bookwyrm/tests/views/test_federation.py @@ -145,11 +145,12 @@ class FederationViews(TestCase): view = views.ImportServerBlocklist.as_view() request = self.factory.post( - "", { + "", + { "json_file": SimpleUploadedFile( "file.json", open("file.json", "rb").read() ) - } + }, ) request.user = self.local_user request.user.is_superuser = True diff --git a/bookwyrm/views/federation.py b/bookwyrm/views/federation.py index 25cd212b..db54cd7a 100644 --- a/bookwyrm/views/federation.py +++ b/bookwyrm/views/federation.py @@ -79,9 +79,7 @@ class ImportServerBlocklist(View): def post(self, request): """ add a server from the admin panel """ - json_data = json.load( - request.FILES["json_file"] - ) + json_data = json.load(request.FILES["json_file"]) failed = [] success_count = 0 for item in json_data: From ba48fcd6f776b907e3b152fb7982ad009d08f8f7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 12 Apr 2021 15:11:01 -0700 Subject: [PATCH 4/4] Fixes markdown formatting --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 670d8b23..ffdf42de 100644 --- a/README.md +++ b/README.md @@ -32,27 +32,27 @@ Federation makes it possible to have small, self-determining communities, in con ### Features Since the project is still in its early stages, the features are growing every day, and there is plenty of room for suggestions and ideas. Open an [issue](https://github.com/mouse-reeve/bookwyrm/issues) to get the conversation going! - - Posting about books +- Posting about books - Compose reviews, with or without ratings, which are aggregated in the book page - Compose other kinds of statuses about books, such as: - - Comments on a book - - Quotes or excerpts + - Comments on a book + - Quotes or excerpts - Reply to statuses - View aggregate reviews of a book across connected BookWyrm instances - Differentiate local and federated reviews and rating in your activity feed - - Track reading activity +- Track reading activity - Shelve books on default "to-read," "currently reading," and "read" shelves - Create custom shelves - Store started reading/finished reading dates, as well as progress updates along the way - Update followers about reading activity (optionally, and with granular privacy controls) - Create lists of books which can be open to submissions from anyone, curated, or only edited by the creator - - Federation with ActivityPub +- Federation with ActivityPub - Broadcast and receive user statuses and activity - Share book data between instances to create a networked database of metadata - Identify shared books across instances and aggregate related content - Follow and interact with users across BookWyrm instances - Inter-operate with non-BookWyrm ActivityPub services (currently, Mastodon is supported) - - Granular privacy controls +- Granular privacy controls - Private, followers-only, and public privacy levels for posting, shelves, and lists - Option for users to manually approve followers - Allow blocking and flagging for moderation