Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2022-02-03 14:09:09 -08:00
commit 36dbf64b12
10 changed files with 106 additions and 15 deletions

View file

@ -22,6 +22,7 @@ class InputHtmlParser(HTMLParser): # pylint: disable=abstract-method
"ol",
"li",
]
self.allowed_attrs = ["href", "rel", "src", "alt"]
self.tag_stack = []
self.output = []
# if the html appears invalid, we just won't allow any at all
@ -30,7 +31,14 @@ class InputHtmlParser(HTMLParser): # pylint: disable=abstract-method
def handle_starttag(self, tag, attrs):
"""check if the tag is valid"""
if self.allow_html and tag in self.allowed_tags:
self.output.append(("tag", self.get_starttag_text()))
allowed_attrs = " ".join(
f'{a}="{v}"' for a, v in attrs if a in self.allowed_attrs
)
reconstructed = f"<{tag}"
if allowed_attrs:
reconstructed += " " + allowed_attrs
reconstructed += ">"
self.output.append(("tag", reconstructed))
self.tag_stack.append(tag)
else:
self.output.append(("data", ""))

View file

@ -28,7 +28,7 @@
<div class="columns">
{% if superlatives.top_rated %}
{% with book=superlatives.top_rated.default_edition rating=top_rated.rating %}
{% with book=superlatives.top_rated.default_edition rating=superlatives.top_rated.rating %}
<div class="column is-one-third is-flex">
<div class="media notification">
<div class="media-left">

View file

@ -56,9 +56,7 @@
{% block modal-footer %}
<button class="button is-primary" type="submit">{% trans "Save" %}</button>
{% if not static %}
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
{% endif %}
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
{% endblock %}
{% block modal-form-close %}</form>{% endblock %}

View file

@ -47,7 +47,7 @@
<span class="icon icon-spinner is-pulled-left" aria-hidden="true"></span>
<span>{% trans "In progress" %}</span>
<span class="is-pulled-right">
<a href="#" class="button is-small">{% trans "Refresh" %}</a>
<a href="{% url 'import-status' job.id %}" class="button is-small">{% trans "Refresh" %}</a>
</span>
</div>
<div class="is-flex">
@ -230,7 +230,7 @@
{% if not legacy %}
<div>
{% include 'snippets/pagination.html' with page=items %}
{% include 'snippets/pagination.html' with page=items path=page_path %}
</div>
{% endif %}
{% endspaceless %}{% endblock %}

View file

@ -70,9 +70,7 @@
{% block modal-footer %}
<button class="button is-primary" type="submit">{% trans "Save" %}</button>
{% if not static %}
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
{% endif %}
{% endblock %}
{% block modal-form-close %}

View file

@ -50,9 +50,7 @@
{% block modal-footer %}
<button class="button is-success" type="submit">{% trans "Submit" %}</button>
{% if not static %}
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
{% endif %}
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
{% endblock %}

View file

@ -1,6 +1,9 @@
""" testing activitystreams """
from datetime import datetime
from unittest.mock import patch
from django.test import TestCase
from django.utils import timezone
from bookwyrm import activitystreams, models
@ -51,13 +54,63 @@ class Activitystreams(TestCase):
"""the abstract base class for stream objects"""
self.assertEqual(
self.test_stream.stream_id(self.local_user),
"{}-test".format(self.local_user.id),
f"{self.local_user.id}-test",
)
self.assertEqual(
self.test_stream.unread_id(self.local_user),
"{}-test-unread".format(self.local_user.id),
f"{self.local_user.id}-test-unread",
)
def test_unread_by_status_type_id(self, *_):
"""stream for status type"""
self.assertEqual(
self.test_stream.unread_by_status_type_id(self.local_user),
f"{self.local_user.id}-test-unread-by-type",
)
def test_get_rank(self, *_):
"""sort order"""
date = datetime(2022, 1, 28, 0, 0, tzinfo=timezone.utc)
status = models.Status.objects.create(
user=self.remote_user,
content="hi",
privacy="direct",
published_date=date,
)
self.assertEqual(
str(self.test_stream.get_rank(status)),
"1643328000.0",
)
def test_get_activity_stream(self, *_):
"""load statuses"""
status = models.Status.objects.create(
user=self.remote_user,
content="hi",
privacy="direct",
)
status2 = models.Comment.objects.create(
user=self.remote_user,
content="hi",
privacy="direct",
book=self.book,
)
models.Comment.objects.create(
user=self.remote_user,
content="hi",
privacy="direct",
book=self.book,
)
with patch("bookwyrm.activitystreams.r.set"), patch(
"bookwyrm.activitystreams.r.delete"
), patch("bookwyrm.activitystreams.ActivityStream.get_store") as redis_mock:
redis_mock.return_value = [status.id, status2.id]
result = self.test_stream.get_activity_stream(self.local_user)
self.assertEqual(result.count(), 2)
self.assertEqual(result.first(), status2)
self.assertEqual(result.last(), status)
self.assertIsInstance(result.first(), models.Comment)
def test_abstractstream_get_audience(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(

View file

@ -52,3 +52,29 @@ class Activitystreams(TestCase):
# yes book, yes audience
result = activitystreams.BooksStream().get_statuses_for_user(self.local_user)
self.assertEqual(list(result), [status])
def test_book_statuses(self, *_):
"""statuses about a book"""
alt_book = models.Edition.objects.create(
title="hi", parent_work=self.book.parent_work
)
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
status = models.Comment.objects.create(
user=self.remote_user, content="hi", privacy="public", book=alt_book
)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
with patch(
"bookwyrm.activitystreams.BooksStream.bulk_add_objects_to_store"
) as redis_mock:
activitystreams.BooksStream().add_book_statuses(self.local_user, self.book)
args = redis_mock.call_args[0]
queryset = args[0]
self.assertEqual(queryset.count(), 1)
self.assertTrue(status in queryset)
self.assertEqual(args[1], f"{self.local_user.id}-books")

View file

@ -24,13 +24,21 @@ class Sanitizer(TestCase):
self.assertEqual(input_text, output)
def test_valid_html_attrs(self):
"""and don't remove attributes"""
"""and don't remove useful attributes"""
input_text = '<a href="fish.com">yes </a> <i>html</i>'
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual(input_text, output)
def test_valid_html_invalid_attrs(self):
"""do remove un-approved attributes"""
input_text = '<a href="fish.com" fish="hello">yes </a> <i>html</i>'
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual(output, '<a href="fish.com">yes </a> <i>html</i>')
def test_invalid_html(self):
"""remove all html when the html is malformed"""
input_text = "<b>yes <i>html</i>"

View file

@ -5,6 +5,7 @@ from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.urls import reverse
from django.views import View
from bookwyrm import models
@ -35,6 +36,7 @@ class ImportTroubleshoot(View):
page.number, on_each_side=2, on_ends=1
),
"complete": True,
"page_path": reverse("import-troubleshoot", args=[job.id]),
}
return TemplateResponse(request, "import/troubleshoot.html", data)