Add user post deletion

Users can delete their posts as long as they don't clear their cookies,
and as long as server-side user sessions are persistent.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-07-13 21:28:07 -07:00
parent 96e8b7752f
commit a4f00e6242
5 changed files with 39 additions and 2 deletions

View File

@@ -25,11 +25,12 @@ class PostForm(ModelForm):
model = Post
fields = ["subject", "name", "text", "capcode", "image"]
def __init__(self, *args, user, board, ip, **kwargs):
def __init__(self, *args, user, board, ip, user_token, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.user = user
self.instance.board = board
self.instance.ip = ip
self.instance.user_token = user_token
self.fields["capcode"].queryset = get_objects_for_user(
self.user, "board.use_capcode"
)

View File

@@ -124,6 +124,10 @@ class Post(models.Model):
# Image width and height
image_width = models.IntegerField(null=True, blank=True)
image_height = models.IntegerField(null=True, blank=True)
# The user token that was used to make this post. This is used for
# verification when a user wants to delete their post. It is not
# particularly secret and does not need to be hashed.
user_token = models.CharField(max_length=30, null=True)
class Meta:
permissions = [

View File

@@ -1,6 +1,9 @@
from typing import Optional, TYPE_CHECKING
from django.utils import timezone
from django.conf import settings
import ipaddress
import random
import string
from board.models import Ban, RangeBan
@@ -45,3 +48,11 @@ def is_banned(ip: str, board: Optional["Board"]) -> bool:
return bool(active)
else:
return False
def generate_user_token() -> str:
"""
Generates a non-secure user token.
User tokens need not be secure so this is a simple implementation.
"""
return "".join(random.choices(string.ascii_letters, k=settings.USER_TOKEN_LENGTH))

View File

@@ -8,7 +8,7 @@ from django.http import Http404, HttpResponseRedirect
from django.http.request import QueryDict
from django.shortcuts import get_object_or_404
from django.views.generic.base import TemplateView
from django.views.generic import detail, edit
from django.views.generic import edit
from django.urls import reverse, reverse_lazy
from django.utils import timezone
@@ -147,6 +147,10 @@ class PostCreateView(CreateView):
def get_form_kwargs(self):
kwargs = super(PostCreateView, self).get_form_kwargs()
kwargs["user"] = self.request.user
if "user_token" not in self.request.session:
# Generate a user token
self.request.session["user_token"] = generate_user_token()
kwargs["user_token"] = self.request.session["user_token"]
return kwargs
def get_success_url(self) -> str:
@@ -213,6 +217,10 @@ class ReplyCreateView(CreateView):
post = get_object_or_404(Post, id=post_id)
kwargs["op"] = post
kwargs["user"] = self.request.user
if "user_token" not in self.request.session:
# Generate a user token
self.request.session["user_token"] = generate_user_token()
kwargs["user_token"] = self.request.session["user_token"]
return kwargs
def get_success_url(self) -> str:
@@ -256,6 +264,13 @@ class PostDeleteView(PermissionRequiredMixin, edit.DeleteView):
success_url = reverse_lazy("board:post_delete_success")
raise_exception = True
def has_permission(self) -> bool:
object = self.get_object()
user_token = self.request.session.get("user_token", None)
return self.request.user.has_perm("board.delete_post") or (
user_token and object.user_token == user_token
)
def form_valid(self, form):
success_url = self.get_success_url()
if form["image_only"].value() != "0":

View File

@@ -174,3 +174,9 @@ BAN_WINDOW_CLOSE_TIMEOUT = 0
# By default, wait 0 seconds. If there is an error, the window won't close
# because it will be redirected elsewhere.
POST_WINDOW_CLOSE_TIMEOUT = 0
# This is the length of a user's token, which is held in a server-side session.
# This token is used to identify a user's individual web client, outside of IP
# address. You probably don't need to change this.
# It should be at most 30, and probably at least 10.
USER_TOKEN_LENGTH = 30