Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2022-07-06 12:33:49 -07:00
commit 5d8a1ec24b
10 changed files with 335 additions and 74 deletions

View file

@ -0,0 +1,25 @@
# Generated by Django 3.2.13 on 2022-07-06 19:16
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0151_alter_report_user"),
]
operations = [
migrations.AlterField(
model_name="report",
name="user",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL,
),
),
]

View file

@ -53,7 +53,7 @@ def comparison_bool(str1, str2, reverse=False):
@register.filter(is_safe=True)
def truncatepath(value, arg):
"""Truncate a path by removing all directories except the first and truncating ."""
"""Truncate a path by removing all directories except the first and truncating"""
path = os.path.normpath(value.name)
path_list = path.split(os.sep)
try:

View file

@ -1,4 +1,5 @@
""" style fixes and lookups for templates """
from collections import namedtuple
import re
from unittest.mock import patch
@ -61,3 +62,18 @@ class UtilitiesTags(TestCase):
self.assertEqual(utilities.get_title(self.book), "Test Book")
book = models.Edition.objects.create(title="Oh", subtitle="oh my")
self.assertEqual(utilities.get_title(book), "Oh: oh my")
def test_comparison_bool(self, *_):
"""just a simple comparison"""
self.assertTrue(utilities.comparison_bool("a", "a"))
self.assertFalse(utilities.comparison_bool("a", "b"))
self.assertFalse(utilities.comparison_bool("a", "a", reverse=True))
self.assertTrue(utilities.comparison_bool("a", "b", reverse=True))
def test_truncatepath(self, *_):
"""truncate a path"""
ValueMock = namedtuple("Value", ("name"))
value = ValueMock("home/one/two/three/four")
self.assertEqual(utilities.truncatepath(value, 2), "home/…ur")
self.assertEqual(utilities.truncatepath(value, "a"), "four")

View file

@ -4,6 +4,7 @@ from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django_celery_beat.models import PeriodicTask, IntervalSchedule
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
@ -28,6 +29,43 @@ class AutomodViews(TestCase):
models.SiteSettings.objects.create()
def test_automod_rules_get(self):
"""there are so many views, this just makes sure it LOADS"""
schedule = IntervalSchedule.objects.create(every=1, period="days")
PeriodicTask.objects.create(
interval=schedule,
name="automod-task",
task="bookwyrm.models.antispam.automod_task",
)
models.AutoMod.objects.create(created_by=self.local_user, string_match="hello")
view = views.AutoMod.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_automod_rules_get_empty_with_schedule(self):
"""there are so many views, this just makes sure it LOADS"""
schedule = IntervalSchedule.objects.create(every=1, period="days")
PeriodicTask.objects.create(
interval=schedule,
name="automod-task",
task="bookwyrm.models.antispam.automod_task",
)
view = views.AutoMod.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_automod_rules_get_empty_without_schedule(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.AutoMod.as_view()
request = self.factory.get("")
@ -45,7 +83,7 @@ class AutomodViews(TestCase):
form.data["string_match"] = "hello"
form.data["flag_users"] = True
form.data["flag_statuses"] = False
form.data["created_by"] = self.local_user
form.data["created_by"] = self.local_user.id
view = views.AutoMod.as_view()
request = self.factory.post("", form.data)
@ -53,6 +91,27 @@ class AutomodViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
rule = models.AutoMod.objects.get()
self.assertTrue(rule.flag_users)
self.assertFalse(rule.flag_statuses)
def test_schedule_automod_task(self):
"""Schedule the task"""
self.assertFalse(IntervalSchedule.objects.exists())
form = forms.IntervalScheduleForm()
form.data["every"] = 1
form.data["period"] = "days"
request = self.factory.post("", form.data)
request.user = self.local_user
request.user.is_superuser = True
response = views.schedule_automod_task(request)
self.assertEqual(response.status_code, 302)
self.assertTrue(IntervalSchedule.objects.exists())

View file

@ -6,7 +6,7 @@ from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
@ -89,52 +89,6 @@ class ReportViews(TestCase):
self.assertEqual(comment.note, "hi")
self.assertEqual(comment.report, report)
def test_report_modal_view(self):
"""a user reports another user"""
request = self.factory.get("")
request.user = self.local_user
result = views.Report.as_view()(request, self.local_user.id)
validate_html(result.render())
def test_make_report(self):
"""a user reports another user"""
form = forms.ReportForm()
form.data["reporter"] = self.local_user.id
form.data["user"] = self.rat.id
request = self.factory.post("", form.data)
request.user = self.local_user
views.Report.as_view()(request)
report = models.Report.objects.get()
self.assertEqual(report.reporter, self.local_user)
self.assertEqual(report.user, self.rat)
def test_report_link(self):
"""a user reports a link as spam"""
book = models.Edition.objects.create(title="hi")
link = models.FileLink.objects.create(
book=book, added_by=self.local_user, url="https://skdjfs.sdf"
)
domain = link.domain
domain.status = "approved"
domain.save()
form = forms.ReportForm()
form.data["reporter"] = self.local_user.id
form.data["user"] = self.rat.id
form.data["links"] = link.id
request = self.factory.post("", form.data)
request.user = self.local_user
views.Report.as_view()(request)
report = models.Report.objects.get()
domain.refresh_from_db()
self.assertEqual(report.links.first().id, link.id)
self.assertEqual(domain.status, "pending")
def test_resolve_report(self):
"""toggle report resolution status"""
report = models.Report.objects.create(reporter=self.local_user, user=self.rat)

View file

@ -48,7 +48,7 @@ class EditBookViews(TestCase):
models.SiteSettings.objects.create()
def test_edit_book_page(self):
def test_edit_book_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.EditBook.as_view()
request = self.factory.get("")
@ -59,18 +59,7 @@ class EditBookViews(TestCase):
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_book_create_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.CreateBook.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_book(self):
def test_edit_book_post(self):
"""lets a user edit a book"""
view = views.EditBook.as_view()
self.local_user.groups.add(self.group)
@ -86,6 +75,23 @@ class EditBookViews(TestCase):
self.book.refresh_from_db()
self.assertEqual(self.book.title, "New Title")
def test_edit_book_post_invalid(self):
"""book form is invalid"""
view = views.EditBook.as_view()
self.local_user.groups.add(self.group)
form = forms.EditionForm(instance=self.book)
form.data["title"] = ""
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
result = view(request, self.book.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
# Title is unchanged
self.book.refresh_from_db()
self.assertEqual(self.book.title, "Example Edition")
def test_edit_book_add_author(self):
"""lets a user edit a book with new authors"""
view = views.EditBook.as_view()
@ -234,3 +240,49 @@ class EditBookViews(TestCase):
self.assertEqual(len(result["author_matches"]), 2)
self.assertEqual(result["author_matches"][0]["name"], "Sappho")
self.assertEqual(result["author_matches"][1]["name"], "Some Guy")
def test_create_book_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.CreateBook.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_create_book_post_existing_work(self):
"""Adding an edition to an existing work"""
author = models.Author.objects.create(name="Sappho")
view = views.CreateBook.as_view()
form = forms.EditionForm()
form.data["title"] = "A Title"
form.data["parent_work"] = self.work.id
form.data["authors"] = [author.id]
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
request.user.is_superuser = True
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
result = view(request)
self.assertEqual(result.status_code, 302)
new_edition = models.Edition.objects.get(title="A Title")
self.assertEqual(new_edition.parent_work, self.work)
self.assertEqual(new_edition.authors.first(), author)
def test_create_book_post_invalid(self):
"""book form is invalid"""
view = views.CreateBook.as_view()
self.local_user.groups.add(self.group)
form = forms.EditionForm(instance=self.book)
form.data["title"] = ""
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
result = view(request)
validate_html(result.render())
self.assertEqual(result.status_code, 200)

View file

@ -112,7 +112,17 @@ class ViewsHelpers(TestCase):
request = self.factory.get("", {"q": "Test Book"}, HTTP_USER_AGENT=USER_AGENT)
self.assertTrue(views.helpers.is_bookwyrm_request(request))
def test_existing_user(self, *_):
def test_handle_remote_webfinger_invalid(self, *_):
"""Various ways you can send a bad query"""
# if there's no query, there's no result
result = views.helpers.handle_remote_webfinger(None)
self.assertIsNone(result)
# malformed user
result = views.helpers.handle_remote_webfinger("noatsymbol")
self.assertIsNone(result)
def test_handle_remote_webfinger_existing_user(self, *_):
"""simple database lookup by username"""
result = views.helpers.handle_remote_webfinger("@mouse@local.com")
self.assertEqual(result, self.local_user)
@ -124,7 +134,19 @@ class ViewsHelpers(TestCase):
self.assertEqual(result, self.local_user)
@responses.activate
def test_load_user(self, *_):
def test_handle_remote_webfinger_load_user_invalid_result(self, *_):
"""find a remote user using webfinger, but fail"""
username = "mouse@example.com"
responses.add(
responses.GET,
f"https://example.com/.well-known/webfinger?resource=acct:{username}",
status=500,
)
result = views.helpers.handle_remote_webfinger("@mouse@example.com")
self.assertIsNone(result)
@responses.activate
def test_handle_remote_webfinger_load_user(self, *_):
"""find a remote user using webfinger"""
username = "mouse@example.com"
wellknown = {
@ -154,7 +176,7 @@ class ViewsHelpers(TestCase):
self.assertIsInstance(result, models.User)
self.assertEqual(result.username, "mouse@example.com")
def test_user_on_blocked_server(self, *_):
def test_handler_remote_webfinger_user_on_blocked_server(self, *_):
"""find a remote user using webfinger"""
models.FederatedServer.objects.create(
server_name="example.com", status="blocked"
@ -163,6 +185,38 @@ class ViewsHelpers(TestCase):
result = views.helpers.handle_remote_webfinger("@mouse@example.com")
self.assertIsNone(result)
@responses.activate
def test_subscribe_remote_webfinger(self, *_):
"""remote subscribe templates"""
query = "mouse@example.com"
response = {
"subject": f"acct:{query}",
"links": [
{
"rel": "self",
"type": "application/activity+json",
"href": "https://example.com/user/mouse",
"template": "hi",
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"type": "application/activity+json",
"href": "https://example.com/user/mouse",
"template": "hello",
},
],
}
responses.add(
responses.GET,
f"https://example.com/.well-known/webfinger?resource=acct:{query}",
json=response,
status=200,
)
template = views.helpers.subscribe_remote_webfinger(query)
self.assertEqual(template, "hello")
template = views.helpers.subscribe_remote_webfinger(f"@{query}")
self.assertEqual(template, "hello")
def test_handle_reading_status_to_read(self, *_):
"""posts shelve activities"""
shelf = self.local_user.shelf_set.get(identifier="to-read")

View file

@ -0,0 +1,109 @@
""" test for app action functionality """
from unittest.mock import patch
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
class ReportViews(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.rat = models.User.objects.create_user(
"rat@local.com",
"rat@mouse.mouse",
"password",
local=True,
localname="rat",
)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"
), patch("bookwyrm.activitystreams.add_status_task.delay"):
self.status = models.Status.objects.create(
user=self.local_user,
content="Test status",
)
models.SiteSettings.objects.create()
def test_report_modal_view(self):
"""a user reports another user"""
request = self.factory.get("")
request.user = self.local_user
result = views.Report.as_view()(request, self.local_user.id)
validate_html(result.render())
def test_report_modal_view_with_status(self):
"""a user reports another user"""
request = self.factory.get("")
request.user = self.local_user
result = views.Report.as_view()(
request, user_id=self.local_user.id, status_id=self.status.id
)
validate_html(result.render())
def test_report_modal_view_with_link_domain(self):
"""a user reports another user"""
link = models.Link.objects.create(
url="http://example.com/hi",
added_by=self.local_user,
)
request = self.factory.get("")
request.user = self.local_user
result = views.Report.as_view()(request, link_id=link.id)
validate_html(result.render())
def test_make_report(self):
"""a user reports another user"""
form = forms.ReportForm()
form.data["reporter"] = self.local_user.id
form.data["user"] = self.rat.id
request = self.factory.post("", form.data)
request.user = self.local_user
views.Report.as_view()(request)
report = models.Report.objects.get()
self.assertEqual(report.reporter, self.local_user)
self.assertEqual(report.user, self.rat)
def test_report_link(self):
"""a user reports a link as spam"""
book = models.Edition.objects.create(title="hi")
link = models.FileLink.objects.create(
book=book, added_by=self.local_user, url="https://skdjfs.sdf"
)
domain = link.domain
domain.status = "approved"
domain.save()
form = forms.ReportForm()
form.data["reporter"] = self.local_user.id
form.data["user"] = self.rat.id
form.data["links"] = link.id
request = self.factory.post("", form.data)
request.user = self.local_user
views.Report.as_view()(request)
report = models.Report.objects.get()
domain.refresh_from_db()
self.assertEqual(report.links.first().id, link.id)
self.assertEqual(domain.status, "pending")

View file

@ -33,8 +33,7 @@ class AutoMod(View):
def post(self, request):
"""add rule"""
form = forms.AutoModRuleForm(request.POST)
success = form.is_valid()
if success:
if form.is_valid():
form.save()
form = forms.AutoModRuleForm()

View file

@ -148,13 +148,6 @@ def handle_reading_status(user, shelf, book, privacy):
status.save()
def is_blocked(viewer, user):
"""is this viewer blocked by the user?"""
if viewer.is_authenticated and viewer in user.blocks.all():
return True
return False
def load_date_in_user_tz_as_utc(date_str: str, user: models.User) -> datetime:
"""ensures that data is stored consistently in the UTC timezone"""
if not date_str: