mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-26 03:21:05 +00:00
Adds automod view
This commit is contained in:
parent
c8b4d5ecf1
commit
12f67dc0ce
9 changed files with 168 additions and 11 deletions
|
@ -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"]
|
||||||
|
|
|
@ -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)),
|
||||||
],
|
],
|
||||||
),
|
),
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
91
bookwyrm/templates/settings/automod/rules.html
Normal file
91
bookwyrm/templates/settings/automod/rules.html
Normal 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 %}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
53
bookwyrm/views/admin/automod.py
Normal file
53
bookwyrm/views/admin/automod.py
Normal 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")
|
Loading…
Reference in a new issue