From 21f199c5482d2aae87058433ce68c2d6930e610a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 8 Mar 2021 18:36:34 -0800 Subject: [PATCH] Make reports --- bookwyrm/forms.py | 6 ++++ ...tcomment.py => 0049_auto_20210309_0156.py} | 12 ++++--- bookwyrm/models/report.py | 11 ++++++- bookwyrm/templates/settings/report.html | 2 ++ .../templates/settings/report_preview.html | 4 +-- .../templates/snippets/report_button.html | 7 ++++ .../snippets/status/status_options.html | 2 +- bookwyrm/templates/snippets/user_options.html | 2 +- bookwyrm/tests/views/test_reports.py | 33 +++++++++++++++++-- bookwyrm/urls.py | 5 +-- bookwyrm/views/__init__.py | 2 +- bookwyrm/views/reports.py | 29 ++++++++++++++-- 12 files changed, 96 insertions(+), 19 deletions(-) rename bookwyrm/migrations/{0049_report_reportcomment.py => 0049_auto_20210309_0156.py} (83%) create mode 100644 bookwyrm/templates/settings/report.html create mode 100644 bookwyrm/templates/snippets/report_button.html diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 380e701f..654130cf 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -231,3 +231,9 @@ class ListForm(CustomForm): class Meta: model = models.List fields = ["user", "name", "description", "curation", "privacy"] + + +class ReportForm(CustomForm): + class Meta: + model = models.Report + fields = ["user", "reporter", "statuses", "note"] diff --git a/bookwyrm/migrations/0049_report_reportcomment.py b/bookwyrm/migrations/0049_auto_20210309_0156.py similarity index 83% rename from bookwyrm/migrations/0049_report_reportcomment.py rename to bookwyrm/migrations/0049_auto_20210309_0156.py index deb8ba6f..494f5bc8 100644 --- a/bookwyrm/migrations/0049_report_reportcomment.py +++ b/bookwyrm/migrations/0049_auto_20210309_0156.py @@ -1,9 +1,10 @@ -# Generated by Django 3.0.7 on 2021-03-09 00:55 +# Generated by Django 3.0.7 on 2021-03-09 01:56 import bookwyrm.models.fields from django.conf import settings from django.db import migrations, models import django.db.models.deletion +import django.db.models.expressions class Migration(migrations.Migration): @@ -23,12 +24,9 @@ class Migration(migrations.Migration): ('note', models.TextField(blank=True, null=True)), ('resolved', models.BooleanField(default=False)), ('reporter', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='reporter', to=settings.AUTH_USER_MODEL)), - ('statuses', models.ManyToManyField(to='bookwyrm.Status')), + ('statuses', models.ManyToManyField(blank=True, null=True, to='bookwyrm.Status')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( name='ReportComment', @@ -45,4 +43,8 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.AddConstraint( + model_name='report', + constraint=models.CheckConstraint(check=models.Q(_negated=True, reporter=django.db.models.expressions.F('user')), name='self_report'), + ), ] diff --git a/bookwyrm/models/report.py b/bookwyrm/models/report.py index afbc356b..e1e8c2a4 100644 --- a/bookwyrm/models/report.py +++ b/bookwyrm/models/report.py @@ -1,5 +1,6 @@ """ flagged for moderation """ from django.db import models +from django.db.models import F, Q from .base_model import BookWyrmModel @@ -11,9 +12,17 @@ class Report(BookWyrmModel): ) note = models.TextField(null=True, blank=True) user = models.ForeignKey("User", on_delete=models.PROTECT) - statuses = models.ManyToManyField("Status") + statuses = models.ManyToManyField("Status", null=True, blank=True) resolved = models.BooleanField(default=False) + class Meta: + """ don't let users report themselves """ + constraints = [ + models.CheckConstraint( + check=~Q(reporter=F('user')), + name='self_report' + ) + ] class ReportComment(BookWyrmModel): """ updates on a report """ diff --git a/bookwyrm/templates/settings/report.html b/bookwyrm/templates/settings/report.html new file mode 100644 index 00000000..1f55906b --- /dev/null +++ b/bookwyrm/templates/settings/report.html @@ -0,0 +1,2 @@ +{% extends 'settings/admin_layout.html' %} +{% load i18n %} diff --git a/bookwyrm/templates/settings/report_preview.html b/bookwyrm/templates/settings/report_preview.html index 67bffe27..b72dd958 100644 --- a/bookwyrm/templates/settings/report_preview.html +++ b/bookwyrm/templates/settings/report_preview.html @@ -2,7 +2,7 @@ {% load i18n %} {% block card-header %}

- report title

+ report title {% endblock %} {% block card-content %} @@ -11,4 +11,4 @@ about this report {% block card-footer %} footer -{% endblock +{% endblock %} diff --git a/bookwyrm/templates/snippets/report_button.html b/bookwyrm/templates/snippets/report_button.html new file mode 100644 index 00000000..5fbaee99 --- /dev/null +++ b/bookwyrm/templates/snippets/report_button.html @@ -0,0 +1,7 @@ +{% load i18n %} +
+ {% csrf_token %} + + + +
diff --git a/bookwyrm/templates/snippets/status/status_options.html b/bookwyrm/templates/snippets/status/status_options.html index 0f099e17..f703ba6e 100644 --- a/bookwyrm/templates/snippets/status/status_options.html +++ b/bookwyrm/templates/snippets/status/status_options.html @@ -25,7 +25,7 @@ {% trans "Send direct message" %}
  • - {% trans "Report status" %} + {% include 'snippets/report_button.html' with user=status.user class="is-fullwidth" %}
  • {% include 'snippets/block_button.html' with user=status.user class="is-fullwidth" %} diff --git a/bookwyrm/templates/snippets/user_options.html b/bookwyrm/templates/snippets/user_options.html index c9fdac0a..585417c7 100644 --- a/bookwyrm/templates/snippets/user_options.html +++ b/bookwyrm/templates/snippets/user_options.html @@ -13,7 +13,7 @@ {% trans "Send direct message" %}
  • - {% trans "Report user" %} + {% include 'snippets/report_button.html' with user=status.user class="is-fullwidth" %}
  • {% include 'snippets/block_button.html' with user=user class="is-fullwidth" %} diff --git a/bookwyrm/tests/views/test_reports.py b/bookwyrm/tests/views/test_reports.py index d35633cb..70414dcb 100644 --- a/bookwyrm/tests/views/test_reports.py +++ b/bookwyrm/tests/views/test_reports.py @@ -3,8 +3,7 @@ from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory -from bookwyrm import models -from bookwyrm import views +from bookwyrm import forms, models, views class ReportViews(TestCase): @@ -20,7 +19,7 @@ class ReportViews(TestCase): local=True, localname="mouse", ) - self.local_user = models.User.objects.create_user( + self.rat = models.User.objects.create_user( "rat@local.com", "rat@mouse.mouse", "password", @@ -35,6 +34,20 @@ class ReportViews(TestCase): request = self.factory.get("") request.user = self.local_user request.user.is_superuser = True + + result = view(request) + self.assertIsInstance(result, TemplateResponse) + result.render() + self.assertEqual(result.status_code, 200) + + def test_reports_page_with_data(self): + """ there are so many views, this just makes sure it LOADS """ + view = views.Reports.as_view() + request = self.factory.get("") + request.user = self.local_user + request.user.is_superuser = True + report = models.Report.objects.create(reporter=self.local_user, user=self.rat) + result = view(request) self.assertIsInstance(result, TemplateResponse) result.render() @@ -53,3 +66,17 @@ class ReportViews(TestCase): self.assertIsInstance(result, TemplateResponse) result.render() self.assertEqual(result.status_code, 200) + + 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.make_report(request) + + report = models.Report.objects.get() + self.assertEqual(report.reporter, self.local_user) + self.assertEqual(report.user, self.rat) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index c7ec7f4b..42b9803d 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -54,14 +54,15 @@ urlpatterns = [ re_path( r"^settings/invites/?$", views.ManageInvites.as_view(), name="settings-invites" ), + re_path(r"^invite/(?P[A-Za-z0-9]+)/?$", views.Invite.as_view()), # moderation re_path(r"^settings/reports/?$", views.Reports.as_view(), name="settings-reports"), re_path( - r"^settings/report/(?P\d+)/?$", + r"^settings/reports/(?P\d+)/?$", views.Report.as_view(), name="settings-report", ), - re_path(r"^invite/(?P[A-Za-z0-9]+)/?$", views.Invite.as_view()), + re_path(r"^report/?$", views.make_report, name="report"), # landing pages re_path(r"^about/?$", views.About.as_view()), path("", views.Home.as_view()), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 36a64ddf..b433dca2 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -20,7 +20,7 @@ from .notifications import Notifications from .outbox import Outbox from .reading import edit_readthrough, create_readthrough, delete_readthrough from .reading import start_reading, finish_reading, delete_progressupdate -from .reports import Report, Reports +from .reports import Report, Reports, make_report from .rss_feed import RssFeed from .password import PasswordResetRequest, PasswordReset, ChangePassword from .search import Search diff --git a/bookwyrm/views/reports.py b/bookwyrm/views/reports.py index 2e374d5e..9eaf9bdc 100644 --- a/bookwyrm/views/reports.py +++ b/bookwyrm/views/reports.py @@ -1,11 +1,12 @@ """ moderation via flagged posts and users """ from django.contrib.auth.decorators import login_required, permission_required -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator from django.views import View +from django.views.decorators.http import require_POST -from bookwyrm import models +from bookwyrm import forms, models # pylint: disable=no-self-use @@ -23,7 +24,7 @@ class Reports(View): def get(self, request): """ view current reports """ - resolved = request.GET.get("resolved") + resolved = request.GET.get("resolved", False) data = { "resolved": resolved, "reports": models.Report.objects.filter(resolved=resolved), @@ -31,6 +32,15 @@ class Reports(View): return TemplateResponse(request, "settings/reports.html", data) +@method_decorator(login_required, name="dispatch") +@method_decorator( + permission_required("bookwyrm.moderate_user", raise_exception=True), + name="dispatch", +) +@method_decorator( + permission_required("bookwyrm.moderate_post", raise_exception=True), + name="dispatch", +) class Report(View): """ view a specific report """ @@ -38,3 +48,16 @@ class Report(View): """ load a report """ data = {"report": get_object_or_404(models.Report, id=report_id)} return TemplateResponse(request, "settings/report.html", data) + + +@login_required +@require_POST +def make_report(request): + """ a user reports something """ + form = forms.ReportForm(request.POST) + if not form.is_valid(): + print(form.errors) + return redirect(request.headers.get("Referer", "/")) + + form.save() + return redirect(request.headers.get("Referer", "/"))