mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-10-31 22:19:00 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
5d8a1ec24b
10 changed files with 335 additions and 74 deletions
25
bookwyrm/migrations/0152_alter_report_user.py
Normal file
25
bookwyrm/migrations/0152_alter_report_user.py
Normal 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,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
109
bookwyrm/tests/views/test_report.py
Normal file
109
bookwyrm/tests/views/test_report.py
Normal 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")
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue