Adds automod view

This commit is contained in:
Mouse Reeve 2022-02-24 11:18:43 -08:00
parent c8b4d5ecf1
commit 12f67dc0ce
9 changed files with 168 additions and 11 deletions

View file

@ -550,3 +550,9 @@ class ReadThroughForm(CustomForm):
class Meta: class Meta:
model = models.ReadThrough model = models.ReadThrough
fields = ["user", "book", "start_date", "finish_date"] fields = ["user", "book", "start_date", "finish_date"]
class AutoModRuleForm(CustomForm):
class Meta:
model = models.AutoMod
fields = ["string_match", "flag_users", "flag_statuses", "created_by"]

View file

@ -1,7 +1,6 @@
# Generated by Django 3.2.12 on 2022-02-18 04:53 # Generated by Django 3.2.12 on 2022-02-24 18:59
from django.conf import settings from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -14,12 +13,12 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='AutoFlag', name='AutoMod',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('flag_users', models.BooleanField(default=False)), ('string_match', models.CharField(max_length=200, unique=True)),
('flag_statuses', models.BooleanField(default=False)), ('flag_users', models.BooleanField(default=True)),
('string_match', models.CharField(max_length=200)), ('flag_statuses', models.BooleanField(default=True)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
], ],
), ),

View file

@ -29,7 +29,7 @@ from .import_job import ImportJob, ImportItem
from .site import SiteSettings, SiteInvite from .site import SiteSettings, SiteInvite
from .site import PasswordReset, InviteRequest from .site import PasswordReset, InviteRequest
from .announcement import Announcement from .announcement import Announcement
from .antispam import EmailBlocklist, IPBlocklist from .antispam import EmailBlocklist, IPBlocklist, AutoMod
from .notification import Notification from .notification import Notification

View file

@ -35,9 +35,9 @@ class IPBlocklist(models.Model):
ordering = ("-created_date",) ordering = ("-created_date",)
class AutoFlag(models.Model): class AutoMod(models.Model):
"""rules to automatically flag suspicious activity""" """rules to automatically flag suspicious activity"""
string_match = models.CharField(max_length=200, unique=True)
flag_users = models.BooleanField(default=True)
flag_statuses = models.BooleanField(default=True)
created_by = models.ForeignKey("User", on_delete=models.PROTECT) created_by = models.ForeignKey("User", on_delete=models.PROTECT)
flag_users = models.BooleanField(default=False)
flag_statuses = models.BooleanField(default=False)
string_match = models.CharField(max_length=200)

View file

@ -0,0 +1,91 @@
{% extends 'settings/layout.html' %}
{% load i18n %}
{% load utilities %}
{% block title %}
{% trans "Auto-moderation rules" %}
{% endblock %}
{% block header %}
{% trans "Auto-moderation rules" %}
{% endblock %}
{% block panel %}
<div class="notification content">
<p>
{% trans "Auto-moderation rules will create reports for any user or status with fields matching the provided string." %}
{% trans "At this time, reports are <em>not</em> being generated automatically, and you must manually trigger a scan." %}
</p>
<button class="button is-warning">{% trans "Run scan" %}</button>
</div>
{% if success %}
<div class="notification is-success is-light">
<span class="icon icon-check" aria-hidden="true"></span>
<span>
{% trans "Successfully added rule" %}
</span>
</div>
{% endif %}
<div class="block table-container">
<table class="table is-striped">
<form action="{% url 'settings-automod' %}" method="POST">
{% csrf_token %}
<input type="hidden" value="{{ request.user.id }}" name="created_by">
<tr>
<th>
<label for="id_string_match">{% trans "String match" %}</label>
</th>
<th>
<label for="id_flag_users">{% trans "Flag users" %}</label>
</th>
<th>
<label for+"id_flag_statuses">{% trans "Flag statuses" %}</label>
</th>
<th>
</th>
</tr>
<tr>
<td>
{{ form.string_match }}
{% include 'snippets/form_errors.html' with errors_list=form.string_match.errors id="desc_string_match" %}
</td>
<td>
{{ form.flag_users }}
</td>
<td>
{{ form.flag_statuses }}
</td>
<td>
<button type="submit" class="button is-primary">{% trans "Add rule" %}</button>
</td>
</tr>
</form>
{% for rule in rules %}
<tr>
<td>
<code>{{ rule.string_match }}</code>
</td>
<td>
{{ rule.flag_users|yesno }}
</td>
<td>
{{ rule.flag_statuses|yesno }}
</td>
<td>
<form action="{% url 'settings-automod-delete' rule.id %}" method="POST">
{% csrf_token %}
<button type="submit" class="button is-danger is-light">
<span class="icon icon-x m-0-mobile" aria-hidden="true"></span>
<span class="is-sr-only-mobile">{% trans "Remove rule" %}</span>
</button>
</form>
</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}

View file

@ -56,6 +56,10 @@
{% url 'settings-reports' as url %} {% url 'settings-reports' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Reports" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Reports" %}</a>
</li> </li>
<li>
{% url 'settings-automod' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Auto-moderation rules" %}</a>
</li>
<li> <li>
{% url 'settings-email-blocks' as url %} {% url 'settings-email-blocks' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Email Blocklist" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Email Blocklist" %}</a>

View file

@ -214,6 +214,9 @@ urlpatterns = [
views.IPBlocklist.as_view(), views.IPBlocklist.as_view(),
name="settings-ip-blocks-delete", name="settings-ip-blocks-delete",
), ),
# auto-moderation rules
re_path(r"^settings/automod/?$", views.AutoMod.as_view(), name="settings-automod"),
re_path(r"^settings/automod/(?P<rule_id>\d+)/delete?$", views.automod_delete, name="settings-automod-delete"),
# moderation # moderation
re_path( re_path(
r"^settings/reports/?$", views.ReportsAdmin.as_view(), name="settings-reports" r"^settings/reports/?$", views.ReportsAdmin.as_view(), name="settings-reports"

View file

@ -2,6 +2,7 @@
# site admin # site admin
from .admin.announcements import Announcements, Announcement from .admin.announcements import Announcements, Announcement
from .admin.announcements import EditAnnouncement, delete_announcement from .admin.announcements import EditAnnouncement, delete_announcement
from .admin.automod import AutoMod, automod_delete
from .admin.dashboard import Dashboard from .admin.dashboard import Dashboard
from .admin.federation import Federation, FederatedServer from .admin.federation import Federation, FederatedServer
from .admin.federation import AddFederatedServer, ImportServerBlocklist from .admin.federation import AddFederatedServer, ImportServerBlocklist

View file

@ -0,0 +1,53 @@
""" moderation via flagged posts and users """
from django.contrib.auth.decorators import login_required, permission_required
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 forms, models
@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",
)
# pylint: disable=no-self-use
class AutoMod(View):
"""Manage automated flagging"""
def get(self, request):
"""view rules"""
data = {"rules": models.AutoMod.objects.all(), "form": forms.AutoModRuleForm()}
return TemplateResponse(request, "settings/automod/rules.html", data)
def post(self, request):
"""add rule"""
form = forms.AutoModRuleForm(request.POST)
success = form.is_valid()
if success:
form.save()
form = forms.AutoModRuleForm()
data = {
"rules": models.AutoMod.objects.all(),
"form": form,
"success": success,
}
return TemplateResponse(request, "settings/automod/rules.html", data)
@require_POST
@permission_required("bookwyrm.moderate_user", raise_exception=True)
@permission_required("bookwyrm.moderate_post", raise_exception=True)
# pylint: disable=unused-argument
def automod_delete(request, rule_id):
""" Remove a rule """
rule = get_object_or_404(models.AutoMod, id=rule_id)
rule.delete()
return redirect("settings-automod")