Files
interchan/board/forms.py
Alek Ratzloff 0ac383ce6c Update PostModifyForm to use permissions to create its fields
Fields are only displayed via the PostModifyForm if the user has
specific permissions to do things, like set stickies.

Also, add PostModifySuccessView that will close the modify window when
the process is complete.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2022-06-30 18:16:08 -07:00

148 lines
4.6 KiB
Python

from django.core.exceptions import ValidationError
from django.conf import settings
from django.db import transaction
from django.db.models import Q
from django import forms
from django.forms import ModelForm, ModelChoiceField
from django.forms.models import fields_for_model
from django.utils import timezone
from board.models import Ban, Post, Report, ReportReason, ReportRecord
from hcaptcha.fields import hCaptchaField
class PostForm(ModelForm):
"""
A form used for new threads for posts.
This requires the board and the IP address to be specified.
"""
hcaptcha = hCaptchaField() if settings.USE_HCAPTCHA else None
class Meta:
model = Post
fields = ["subject", "name", "text", "image"]
def __init__(self, *args, user, board, ip, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.user = user
self.instance.board = board
self.instance.ip = ip
class ReplyForm(PostForm):
"""
A form used for replies to posts.
This requires the OP post, the reply post, the board, and the IP address be
specified.
"""
hcaptcha = hCaptchaField() if settings.USE_HCAPTCHA else None
class Meta:
model = Post
fields = ["name", "text", "bump", "capcode", "image"]
def __init__(self, *args, op, **kwargs):
super(ReplyForm, self).__init__(*args, **kwargs)
self.instance.op = op
def clean(self):
super().clean()
# TODO
# Check if the user has the right permissions to use the selected capcode
capcode = self.cleaned_data["capcode"]
if capcode:
if not self.user or not self.user.has_perm("board.use_capcode", capcode):
raise ValidationError("Could not create post")
class ReportForm(ModelForm):
"""
A form used to create reports on posts.
This requires the board and the IP address to be specified.
"""
# uses report_form.html
class Meta:
model = Report
fields = ["reason"]
def __init__(self, *args, op, board, ip, **kwargs):
super(ReportForm, self).__init__(*args, **kwargs)
self.instance.ip = ip
self.op = op
queryset = ReportReason.objects.filter(Q(board=None) | Q(board=board))
self.fields["reason"] = ModelChoiceField(queryset=queryset)
def clean(self):
# Get or create the record before creating the model
with transaction.atomic():
try:
record = ReportRecord.objects.get(post=self.op)
except ReportRecord.DoesNotExist:
record = ReportRecord.objects.create(post=self.op)
self.instance.record = record
return super(ReportForm, self).clean()
class BanForm(ModelForm):
"""
A form used to create bans based on specific posts.
"""
# uses ban_form.html
duration = forms.IntegerField(label="Duration (days)", min_value=1, required=False)
class Meta:
model = Ban
fields = ["ban_reason", "board"]
def __init__(self, *args, op, **kwargs):
super(BanForm, self).__init__(*args, **kwargs)
self.op = op
self.instance.ip = op.ip
self.instance.post_id = op.id
def clean(self):
super(BanForm, self).clean()
now = timezone.now()
duration = self.cleaned_data["duration"]
if duration:
expires = now + timezone.timedelta(days=duration)
else:
expires = None
self.instance.expires = expires
class PostModifyForm(ModelForm):
"""
A form used to modify the attributes of a post (sticky, locked, sink, etc)
"""
class Meta:
model = Post
# we specify fields up here too because otherwise they won't be
# recognized by the form to update values
fields: list[str] = ["sticky"]
def __init__(self, *args, user, **kwargs):
super(PostModifyForm, self).__init__(*args, **kwargs)
self.user = user
fields = []
if self.user.has_perm("board.set_sticky"):
fields += ["sticky"]
# NOTE:
# We do *not* need to check permissions against these fields we're
# setting down here in the self.clean() function in the case that a
# malicious actor has access to the modify form and injects a "sticky"
# value to their modify request.
#
# We specify fields up in the Meta class, but we reset them down here.
# If the field isn't present in this list, then it doesn't get updated.
# If the field isn't present in the above list, then it doesn't get updated.
self.fields = fields_for_model(Post, fields)