From 0ac383ce6c280fc086d57f912091c41e74934bed Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Thu, 30 Jun 2022 18:16:08 -0700 Subject: [PATCH] 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 --- board/forms.py | 24 ++++++++++-- board/templates/board/base.html | 7 +++- .../templates/board/post_modify_success.html | 33 ++++++++++++++++ board/templates/board/post_modify_view.html | 2 +- board/templates/board/post_snippet.html | 4 +- board/urls.py | 3 ++ board/views.py | 38 ++++++++++++++++--- 7 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 board/templates/board/post_modify_success.html diff --git a/board/forms.py b/board/forms.py index bb4b557..55fef39 100644 --- a/board/forms.py +++ b/board/forms.py @@ -4,6 +4,7 @@ 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 @@ -124,8 +125,23 @@ class PostModifyForm(ModelForm): class Meta: model = Post - fields = ["bump", "sticky"] + # we specify fields up here too because otherwise they won't be + # recognized by the form to update values + fields: list[str] = ["sticky"] - def clean(self): - super(PostModifyForm, self).clean() - print(self.fields["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) diff --git a/board/templates/board/base.html b/board/templates/board/base.html index 30b9b68..0160acd 100644 --- a/board/templates/board/base.html +++ b/board/templates/board/base.html @@ -12,8 +12,11 @@ - {% if perms.board.create_ban %} - + {% if perms.board.add_ban %} + + {% endif %} + {% if can_modify %} + {% endif %} {% block extrajs %}{% endblock %} diff --git a/board/templates/board/post_modify_success.html b/board/templates/board/post_modify_success.html new file mode 100644 index 0000000..d79b679 --- /dev/null +++ b/board/templates/board/post_modify_success.html @@ -0,0 +1,33 @@ +{% extends "board/base.html" %} +{% load i18n static %} +{# Title #} +{% block title %}{% translate "Post modify success" %}{% endblock %} +{# Body #} +{% block content %} +
+ {# We do not use pluralize filter for "seconds" because it's a pain to get it to translate. #} + {% blocktranslate %}Post has been modified. This window will close in {{window_timeout}} second(s).{% endblocktranslate %} +
+ + +{% endblock %} \ No newline at end of file diff --git a/board/templates/board/post_modify_view.html b/board/templates/board/post_modify_view.html index 78543d5..fec8cbc 100644 --- a/board/templates/board/post_modify_view.html +++ b/board/templates/board/post_modify_view.html @@ -5,7 +5,7 @@
{% csrf_token %} - {% if perms.board.can_sticky %} + {% if perms.board.set_sticky %} diff --git a/board/templates/board/post_snippet.html b/board/templates/board/post_snippet.html index f90f73a..2583eca 100644 --- a/board/templates/board/post_snippet.html +++ b/board/templates/board/post_snippet.html @@ -3,10 +3,10 @@
diff --git a/board/urls.py b/board/urls.py index 39eeeb2..a1e14d1 100644 --- a/board/urls.py +++ b/board/urls.py @@ -22,6 +22,9 @@ urlpatterns = [ path("banned", BannedView.as_view(), name="banned"), # Other moderation pages path("modify//", PostModifyView.as_view(), name="post_modify"), + path( + "modify/success/", PostModifySuccessView.as_view(), name="post_modify_success" + ), ] # TODO - make this conditional so we can serve images up with whatever server we want urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/board/views.py b/board/views.py index a2ec22f..6feece7 100644 --- a/board/views.py +++ b/board/views.py @@ -24,6 +24,7 @@ __all__ = ( "BoardView", "PostCreateView", "PostModifyView", + "PostModifySuccessView", "PostView", "PostSuccessView", "ReplyCreateView", @@ -35,6 +36,13 @@ __all__ = ( User = get_user_model() +def can_modify(user): + if not user: + return False + # TODO add more permissions as required + return user.has_perm("board.set_sticky") + + class BannedView(TemplateView): template_name = "board/banned.html" @@ -117,6 +125,7 @@ class BoardView(TemplateView): kwargs["pages"] = range(1, last_page + 1) kwargs["last_page"] = last_page kwargs["max_upload_size"] = settings.MAX_UPLOAD_SIZE + kwargs["can_modify"] = can_modify(self.request.user) return super(BoardView, self).get_context_data(**kwargs) @@ -135,6 +144,7 @@ class PostCreateView(CreateView): context["capcodes"] = get_objects_for_user( get_user(self.request), "board.use_capcode" ) + kwargs["can_modify"] = can_modify(self.request.user) return context def get_form_kwargs(self): @@ -152,19 +162,34 @@ class PostModifyView(PermissionRequiredMixin, edit.UpdateView): model = Post form_class = PostModifyForm template_name = "board/post_modify_view.html" + success_url = reverse_lazy("board:post_modify_success") def has_permission(self) -> bool: - user = self.request.user - if not user: - return False - # TODO add more permissions as required - return user.has_perm("board.can_sticky") + return can_modify(self.request.user) def dispatch(self, request, *args, **kwargs): self.post_obj = get_object_or_404(Post, id=kwargs["pk"]) self.board = self.post_obj.board return super(PostModifyView, self).dispatch(request, *args, **kwargs) + def get_form_kwargs(self) -> Dict[str, Any]: + kwargs = super(PostModifyView, self).get_form_kwargs() + kwargs["user"] = self.request.user + return kwargs + + +class PostModifySuccessView(PermissionRequiredMixin, TemplateView): + template_name = "board/post_modify_success.html" + + def has_permission(self) -> bool: + return can_modify(self.request.user) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["window_timeout"] = settings.BAN_WINDOW_CLOSE_TIMEOUT + context["can_modify"] = self.has_permission() + return context + class ReplyCreateView(CreateView): model = Post @@ -183,6 +208,7 @@ class ReplyCreateView(CreateView): context["capcodes"] = get_objects_for_user( get_user(self.request), "board.use_capcode" ) + kwargs["can_modify"] = can_modify(self.request.user) return context def get_form_kwargs(self): @@ -262,7 +288,7 @@ class ReportSuccessView(TemplateView): class BanCreateView(PermissionRequiredMixin, edit.CreateView): model = Ban form_class = BanForm - permission_required = "ban.create" + permission_required = "board.add_ban" success_url = reverse_lazy("board:ban_success") def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
{{form.sticky.label_tag}} {{form.sticky}}