Add report record admin and template search
When creating a ban, you can type in to do a search, this is useful for quickly banning users. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
from django import forms
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.http.response import HttpResponseRedirect
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from board.models import Ban, Board, Post, RangeBan, ReportReason, ReportRecord
|
from board.models import (
|
||||||
|
Ban,
|
||||||
|
BanTemplate,
|
||||||
|
Board,
|
||||||
|
Post,
|
||||||
|
RangeBan,
|
||||||
|
ReportReason,
|
||||||
|
ReportRecord,
|
||||||
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Admin sites
|
# Admin sites
|
||||||
@@ -24,10 +29,6 @@ class ReportReasonAdmin(admin.ModelAdmin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BanFromReportForm(forms.ModelForm):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ReportRecord)
|
@admin.register(ReportRecord)
|
||||||
class ReportRecordAdmin(admin.ModelAdmin):
|
class ReportRecordAdmin(admin.ModelAdmin):
|
||||||
ordering = (
|
ordering = (
|
||||||
@@ -76,3 +77,8 @@ class RangeBanAdmin(admin.ModelAdmin):
|
|||||||
@admin.register(Ban)
|
@admin.register(Ban)
|
||||||
class BanAdmin(admin.ModelAdmin):
|
class BanAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(BanTemplate)
|
||||||
|
class BanTemplateAdmin(admin.ModelAdmin):
|
||||||
|
ordering = ("board__url", "name")
|
||||||
|
|||||||
@@ -311,11 +311,21 @@ class Ban(BanCommon):
|
|||||||
|
|
||||||
|
|
||||||
class BanTemplate(models.Model):
|
class BanTemplate(models.Model):
|
||||||
|
# The name of this template
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
# The reason for this ban
|
# The reason for this ban
|
||||||
ban_reason = models.TextField(blank=False)
|
ban_reason = models.TextField(blank=False)
|
||||||
# The duration of the ban
|
# The duration of the ban, in days
|
||||||
duration = models.DurationField()
|
duration = models.IntegerField(blank=True, null=True)
|
||||||
|
# The board that this template is for, or none.
|
||||||
|
board = models.ForeignKey("Board", on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
def create_ban(self, ip: str) -> Ban:
|
def create_ban(self, ip: str) -> Ban:
|
||||||
expires = timezone.now() + self.duration
|
expires = timezone.now() + self.duration
|
||||||
return Ban.objects.create(ip=ip, ban_reason=self.ban_reason, expires=expires)
|
return Ban.objects.create(ip=ip, ban_reason=self.ban_reason, expires=expires)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.board:
|
||||||
|
return f"/{self.board.url}/ - {self.name}"
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form id="form" action="{% url 'board:ban_create' url=board.url id=post.id %}" method="post">
|
<form id="form" action="{% url 'board:ban_create' url=board.url id=post.id %}" method="post" autocomplete="off">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -17,13 +17,28 @@
|
|||||||
<th>IP:</th>
|
<th>IP:</th>
|
||||||
<td>{{post.ip}}</td>
|
<td>{{post.ip}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% translate 'Template search' %}:</th>
|
||||||
|
<td><input id="template_search" type="text" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% translate 'Template' %}</th>
|
||||||
|
<td>
|
||||||
|
<select id="templates">
|
||||||
|
<option class="template_option" data-reason="" data-duration="">Custom</option>
|
||||||
|
{% for template in templates %}
|
||||||
|
<option class="template_option" data-reason="{{template.ban_reason}}" data-duration="{{template.duration}}">{{template.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{{form.as_table}}
|
{{form.as_table}}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Previous bans" %}</th>
|
<th>{% translate "Previous bans" %}:</th>
|
||||||
<td>{{previous_bans|length}}</td>
|
<td>{{previous_bans|length}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Current bans" %}</th>
|
<th>{% translate "Current bans" %}:</th>
|
||||||
<td id="current_bans">{{current_bans|length}}</td>
|
<td id="current_bans">{{current_bans|length}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -35,7 +50,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
function submitConfirm(e) {
|
function submitConfirm(e) {
|
||||||
console.log($("#current_bans").text());
|
|
||||||
if($("#current_bans").text() !== '0') {
|
if($("#current_bans").text() !== '0') {
|
||||||
let result = window.confirm("There is already at least one ban for this IP address on this board, are you sure you want to continue?");
|
let result = window.confirm("There is already at least one ban for this IP address on this board, are you sure you want to continue?");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -45,6 +59,45 @@ function submitConfirm(e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function templateSelect(e) {
|
||||||
|
let selected = $($(e.target).find(":selected"));
|
||||||
|
// uh oh, mixing django templates and JS
|
||||||
|
let banReason = $("#{{form.ban_reason.auto_id}}");
|
||||||
|
let duration = $("#{{form.duration.auto_id}}");
|
||||||
|
banReason.val(selected.attr("data-reason"));
|
||||||
|
duration.val(selected.attr("data-duration"));
|
||||||
|
|
||||||
|
if(selected.val() === "Custom") {
|
||||||
|
// unlock the controls
|
||||||
|
banReason.attr("readonly", false);
|
||||||
|
duration.attr("readonly", false);
|
||||||
|
} else {
|
||||||
|
// lock all controls
|
||||||
|
banReason.attr("readonly", true);
|
||||||
|
duration.attr("readonly", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function templateSearch(e) {
|
||||||
|
let search = $(e.target).val();
|
||||||
|
let element = $("#templates option").toArray().find(element => {
|
||||||
|
let re = new RegExp(search, "i");
|
||||||
|
return element.value.search(re) !== -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(typeof element === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#templates")
|
||||||
|
.val(element.value)
|
||||||
|
.trigger("change");
|
||||||
|
}
|
||||||
|
|
||||||
$("#submit").on("click", submitConfirm);
|
$("#submit").on("click", submitConfirm);
|
||||||
|
$("#templates").on("change", templateSelect);
|
||||||
|
$("#template_search").on("input propertychange paste", templateSearch);
|
||||||
|
$("#template_search").select();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
|
from django.db.models import Q
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
@@ -8,7 +9,7 @@ from django.views.generic.edit import CreateView
|
|||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from board.forms import BanForm, PostForm, ReplyForm, ReportForm
|
from board.forms import BanForm, PostForm, ReplyForm, ReportForm
|
||||||
from board.models import Ban, Board, Post, Report
|
from board.models import Ban, BanTemplate, Board, Post, Report
|
||||||
from board.utils import get_client_ip, get_ip_bans
|
from board.utils import get_client_ip, get_ip_bans
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@@ -186,6 +187,9 @@ class BanCreateView(PermissionRequiredMixin, CreateView):
|
|||||||
context["current_bans"] = [
|
context["current_bans"] = [
|
||||||
ban for ban in bans if ban.expires is None or ban.expires > now
|
ban for ban in bans if ban.expires is None or ban.expires > now
|
||||||
]
|
]
|
||||||
|
context["templates"] = BanTemplate.objects.filter(
|
||||||
|
Q(board=self.board) | Q(board=None)
|
||||||
|
)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user