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:
@@ -25,11 +25,12 @@ class PostForm(ModelForm):
|
|||||||
model = Post
|
model = Post
|
||||||
fields = ["subject", "name", "text", "capcode", "image"]
|
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)
|
super(PostForm, self).__init__(*args, **kwargs)
|
||||||
self.user = user
|
self.user = user
|
||||||
self.instance.board = board
|
self.instance.board = board
|
||||||
self.instance.ip = ip
|
self.instance.ip = ip
|
||||||
|
self.instance.user_token = user_token
|
||||||
self.fields["capcode"].queryset = get_objects_for_user(
|
self.fields["capcode"].queryset = get_objects_for_user(
|
||||||
self.user, "board.use_capcode"
|
self.user, "board.use_capcode"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ class Post(models.Model):
|
|||||||
# Image width and height
|
# Image width and height
|
||||||
image_width = models.IntegerField(null=True, blank=True)
|
image_width = models.IntegerField(null=True, blank=True)
|
||||||
image_height = 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:
|
class Meta:
|
||||||
permissions = [
|
permissions = [
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.conf import settings
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
from board.models import Ban, RangeBan
|
from board.models import Ban, RangeBan
|
||||||
|
|
||||||
@@ -45,3 +48,11 @@ def is_banned(ip: str, board: Optional["Board"]) -> bool:
|
|||||||
return bool(active)
|
return bool(active)
|
||||||
else:
|
else:
|
||||||
return False
|
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))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.http import Http404, HttpResponseRedirect
|
|||||||
from django.http.request import QueryDict
|
from django.http.request import QueryDict
|
||||||
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
|
||||||
from django.views.generic import detail, edit
|
from django.views.generic import edit
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@@ -147,6 +147,10 @@ class PostCreateView(CreateView):
|
|||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(PostCreateView, self).get_form_kwargs()
|
kwargs = super(PostCreateView, self).get_form_kwargs()
|
||||||
kwargs["user"] = self.request.user
|
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
|
return kwargs
|
||||||
|
|
||||||
def get_success_url(self) -> str:
|
def get_success_url(self) -> str:
|
||||||
@@ -213,6 +217,10 @@ class ReplyCreateView(CreateView):
|
|||||||
post = get_object_or_404(Post, id=post_id)
|
post = get_object_or_404(Post, id=post_id)
|
||||||
kwargs["op"] = post
|
kwargs["op"] = post
|
||||||
kwargs["user"] = self.request.user
|
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
|
return kwargs
|
||||||
|
|
||||||
def get_success_url(self) -> str:
|
def get_success_url(self) -> str:
|
||||||
@@ -256,6 +264,13 @@ class PostDeleteView(PermissionRequiredMixin, edit.DeleteView):
|
|||||||
success_url = reverse_lazy("board:post_delete_success")
|
success_url = reverse_lazy("board:post_delete_success")
|
||||||
raise_exception = True
|
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):
|
def form_valid(self, form):
|
||||||
success_url = self.get_success_url()
|
success_url = self.get_success_url()
|
||||||
if form["image_only"].value() != "0":
|
if form["image_only"].value() != "0":
|
||||||
|
|||||||
@@ -174,3 +174,9 @@ BAN_WINDOW_CLOSE_TIMEOUT = 0
|
|||||||
# By default, wait 0 seconds. If there is an error, the window won't close
|
# By default, wait 0 seconds. If there is an error, the window won't close
|
||||||
# because it will be redirected elsewhere.
|
# because it will be redirected elsewhere.
|
||||||
POST_WINDOW_CLOSE_TIMEOUT = 0
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user