Merge branch 'main' into notifications
This commit is contained in:
commit
5a6ef7ccd8
29 changed files with 441 additions and 96 deletions
|
@ -45,7 +45,8 @@ def moderation_report_email(report):
|
|||
"""a report was created"""
|
||||
data = email_data()
|
||||
data["reporter"] = report.reporter.localname or report.reporter.username
|
||||
data["reportee"] = report.user.localname or report.user.username
|
||||
if report.user:
|
||||
data["reportee"] = report.user.localname or report.user.username
|
||||
data["report_link"] = report.remote_id
|
||||
|
||||
for admin in models.User.objects.filter(
|
||||
|
|
|
@ -10,3 +10,4 @@ from .landing import *
|
|||
from .links import *
|
||||
from .lists import *
|
||||
from .status import *
|
||||
from .user_admin import *
|
||||
|
|
|
@ -4,12 +4,6 @@ from .custom_form import CustomForm
|
|||
|
||||
|
||||
# pylint: disable=missing-class-docstring
|
||||
class UserGroupForm(CustomForm):
|
||||
class Meta:
|
||||
model = models.User
|
||||
fields = ["groups"]
|
||||
|
||||
|
||||
class GroupForm(CustomForm):
|
||||
class Meta:
|
||||
model = models.Group
|
||||
|
|
10
bookwyrm/forms/user_admin.py
Normal file
10
bookwyrm/forms/user_admin.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
""" using django model forms """
|
||||
from bookwyrm import models
|
||||
from .custom_form import CustomForm
|
||||
|
||||
|
||||
# pylint: disable=missing-class-docstring
|
||||
class UserGroupForm(CustomForm):
|
||||
class Meta:
|
||||
model = models.User
|
||||
fields = ["groups"]
|
24
bookwyrm/migrations/0151_alter_report_user.py
Normal file
24
bookwyrm/migrations/0151_alter_report_user.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-05 23:54
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0150_readthrough_stopped_date"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="report",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
]
|
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,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -11,7 +11,7 @@ class Report(BookWyrmModel):
|
|||
"User", related_name="reporter", on_delete=models.PROTECT
|
||||
)
|
||||
note = models.TextField(null=True, blank=True)
|
||||
user = models.ForeignKey("User", on_delete=models.PROTECT)
|
||||
user = models.ForeignKey("User", on_delete=models.PROTECT, null=True, blank=True)
|
||||
status = models.ForeignKey(
|
||||
"Status",
|
||||
null=True,
|
||||
|
|
|
@ -42,7 +42,11 @@
|
|||
<a href="{{ link.url }}" target="_blank" rel="noopener noreferrer">{{ link.url }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{% if link.added_by %}
|
||||
<a href="{% url 'user-feed' link.added_by.id %}">{{ link.added_by.display_name }}</a>
|
||||
{% else %}
|
||||
<em>{% trans "Unknown user" %}</em>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ link.filelink.filetype }}
|
||||
|
@ -50,7 +54,7 @@
|
|||
<td>
|
||||
{{ link.domain.name }}
|
||||
<p>
|
||||
<a href="{% url 'report-link' link.added_by.id link.id %}">{% trans "Report spam" %}</a>
|
||||
<a href="{% url 'report-link' link.id %}">{% trans "Report spam" %}</a>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -19,7 +19,7 @@ Is that where you'd like to go?
|
|||
{% block modal-footer %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<div class="is-flex-grow-1">
|
||||
<a href="{% url 'report-link' link.added_by.id link.id %}">{% trans "Report spam" %}</a>
|
||||
<a href="{% url 'report-link' link.id %}">{% trans "Report spam" %}</a>
|
||||
</div>
|
||||
|
||||
<button type="button" class="button" data-modal-close>{% trans "Cancel" %}</button>
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
|
||||
{% block content %}
|
||||
<p>
|
||||
{% blocktrans %}@{{ reporter }} has flagged behavior by @{{ reportee }} for moderation. {% endblocktrans %}
|
||||
{% if report_link %}
|
||||
|
||||
{% blocktrans trimmed %}
|
||||
@{{ reporter }} has flagged a link domain for moderation.
|
||||
{% endblocktrans %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% blocktrans trimmed %}
|
||||
@{{ reporter }} has flagged behavior by @{{ reportee }} for moderation.
|
||||
{% endblocktrans %}
|
||||
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% trans "View report" as text %}
|
||||
|
|
|
@ -2,7 +2,15 @@
|
|||
{% load i18n %}
|
||||
{% block content %}
|
||||
|
||||
{% blocktrans %}@{{ reporter}} has flagged behavior by @{{ reportee }} for moderation. {% endblocktrans %}
|
||||
{% if report_link %}
|
||||
{% blocktrans trimmed %}
|
||||
@{{ reporter }} has flagged a link domain for moderation.
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans trimmed %}
|
||||
@{{ reporter }} has flagged behavior by @{{ reportee }} for moderation.
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
||||
{% trans "View report" %}
|
||||
{{ report_link }}
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
<a href="{{ link.url }}" target="_blank" rel="noopener noreferrer">{{ link.url }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{% if link.added_by %}
|
||||
<a href="{% url 'settings-user' link.added_by.id %}">@{{ link.added_by|username }}</a>
|
||||
{% else %}
|
||||
<em>{% trans "Unknown user" %}</em>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if link.filelink.filetype %}
|
||||
|
|
|
@ -55,9 +55,11 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if report.user %}
|
||||
{% include 'settings/users/user_info.html' with user=report.user %}
|
||||
|
||||
{% include 'settings/users/user_moderation_actions.html' with user=report.user %}
|
||||
{% endif %}
|
||||
|
||||
<div class="block">
|
||||
<h3 class="title is-4">{% trans "Moderator Comments" %}</h3>
|
||||
|
|
|
@ -9,9 +9,15 @@ Report #{{ report_id }}: Status posted by @{{ username }}
|
|||
|
||||
{% elif report.links.exists %}
|
||||
|
||||
{% blocktrans trimmed with report_id=report.id username=report.user|username %}
|
||||
Report #{{ report_id }}: Link added by @{{ username }}
|
||||
{% endblocktrans %}
|
||||
{% if report.user %}
|
||||
{% 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 %}
|
||||
Report #{{ report_id }}: Link domain
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
|
|
|
@ -72,6 +72,12 @@
|
|||
<span class="icon icon-check"></span>
|
||||
</span>
|
||||
{% trans "Active" %}
|
||||
{% elif user.deactivation_reason == "moderator_deletion" or user.deactivation_reason == "self_deletion" %}
|
||||
<span class="tag is-danger" aria-hidden="true">
|
||||
<span class="icon icon-x"></span>
|
||||
</span>
|
||||
{% trans "Deleted" %}
|
||||
<span class="help">({{ user.get_deactivation_reason_display }})</span>
|
||||
{% else %}
|
||||
<span class="tag is-warning" aria-hidden="true">
|
||||
<span class="icon icon-x"></span>
|
||||
|
|
|
@ -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")
|
|
@ -287,7 +287,7 @@ urlpatterns = [
|
|||
name="report-status",
|
||||
),
|
||||
re_path(
|
||||
r"^report/(?P<user_id>\d+)/link/(?P<link_id>\d+)?$",
|
||||
r"^report/link/(?P<link_id>\d+)?$",
|
||||
views.Report.as_view(),
|
||||
name="report-link",
|
||||
),
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -77,8 +77,13 @@ class UserAdmin(View):
|
|||
def post(self, request, user):
|
||||
"""update user group"""
|
||||
user = get_object_or_404(models.User, id=user)
|
||||
form = forms.UserGroupForm(request.POST, instance=user)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
|
||||
if request.POST.get("groups") == "":
|
||||
user.groups.set([])
|
||||
form = forms.UserGroupForm(instance=user)
|
||||
else:
|
||||
form = forms.UserGroupForm(request.POST, instance=user)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
data = {"user": user, "group_form": form}
|
||||
return TemplateResponse(request, "settings/users/user.html", data)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -13,9 +13,13 @@ from bookwyrm import emailing, forms, models
|
|||
class Report(View):
|
||||
"""Make reports"""
|
||||
|
||||
def get(self, request, user_id, status_id=None, link_id=None):
|
||||
def get(self, request, user_id=None, status_id=None, link_id=None):
|
||||
"""static view of report modal"""
|
||||
data = {"user": get_object_or_404(models.User, id=user_id)}
|
||||
data = {"user": None}
|
||||
if user_id:
|
||||
# but normally we should have an error if the user is not found
|
||||
data["user"] = get_object_or_404(models.User, id=user_id)
|
||||
|
||||
if status_id:
|
||||
data["status"] = status_id
|
||||
if link_id:
|
||||
|
|
3
bw-dev
3
bw-dev
|
@ -103,6 +103,9 @@ case "$CMD" in
|
|||
pytest)
|
||||
runweb pytest --no-cov-on-fail "$@"
|
||||
;;
|
||||
pytest_coverage_report)
|
||||
runweb pytest -n 3 --cov-report term-missing "$@"
|
||||
;;
|
||||
collectstatic)
|
||||
runweb python manage.py collectstatic --no-input
|
||||
;;
|
||||
|
|
|
@ -2,7 +2,7 @@ aiohttp==3.8.1
|
|||
bleach==5.0.1
|
||||
celery==5.2.2
|
||||
colorthief==0.2.1
|
||||
Django==3.2.13
|
||||
Django==3.2.14
|
||||
django-celery-beat==2.2.1
|
||||
django-compressor==2.4.1
|
||||
django-imagekit==4.1.0
|
||||
|
|
Loading…
Add table
Reference in a new issue